blob: b34fe69d0dcb4ec96984ed04d7e1c9e8689bac1c [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.
library fasta.uri_translator_impl;
import 'dart:async' show Future;
import 'dart:convert' show JSON;
import 'package:front_end/file_system.dart'
show FileSystem, FileSystemException;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/fasta_codes.dart';
import 'package:front_end/src/fasta/severity.dart' show Severity;
import 'package:front_end/src/fasta/uri_translator.dart';
import 'package:package_config/packages_file.dart' as packages_file show parse;
import 'package:package_config/packages.dart' show Packages;
import 'package:package_config/src/packages_impl.dart' show MapPackages;
import 'deprecated_problems.dart' show deprecated_inputError;
/// Read the JSON file with defined SDK libraries from the given [uri] in the
/// [fileSystem] and return the mapping from parsed Dart library names (e.g.
/// `math`) to file URIs.
Future<Map<String, Uri>> computeDartLibraries(
FileSystem fileSystem, Uri uri) async {
if (uri == null) return const <String, Uri>{};
Map<String, String> libraries = JSON
.decode(await fileSystem.entityForUri(uri).readAsString())["libraries"];
Map<String, Uri> result = <String, Uri>{};
libraries.forEach((String name, String path) {
result[name] = uri.resolveUri(new Uri.file(path));
});
return result;
}
Future<Map<String, List<Uri>>> computeDartPatches(
FileSystem fileSystem, Uri uri) async {
// TODO(ahe): Read patch information.
return const <String, List<Uri>>{};
}
/// Implementation of [UriTranslator] for absolute `dart` and `package` URIs.
class UriTranslatorImpl implements UriTranslator {
/// Mapping from Dart library names (e.g. `math`) to file URIs.
final Map<String, Uri> dartLibraries;
// TODO(ahe): We probably want this to be `Map<String, Uri>`, that is, just
// one patch library (with parts).
/// Mapping from Dart library names to the file URIs of patches to apply.
final Map<String, List<Uri>> dartPatches;
/// Mapping from package names (e.g. `angular`) to the file URIs.
final Packages packages;
UriTranslatorImpl(this.dartLibraries, this.dartPatches, this.packages);
@override
List<Uri> getDartPatches(String libraryName) => dartPatches[libraryName];
@override
bool isPlatformImplementation(Uri uri) {
if (uri.scheme != "dart") return false;
String path = uri.path;
return dartLibraries[path] == null || path.startsWith("_");
}
@override
// TODO(sigmund, ahe): consider expanding this API to include an error
// callback, so we can provide an error location when one is available. For
// example, if the error occurs in an `import`.
Uri translate(Uri uri) {
if (uri.scheme == "dart") return _translateDartUri(uri);
if (uri.scheme == "package") return _translatePackageUri(uri);
return null;
}
/// Return the file URI that corresponds to the given `dart` URI, or `null`
/// if there is no corresponding Dart library registered.
Uri _translateDartUri(Uri uri) {
if (!uri.isScheme('dart')) return null;
String path = uri.path;
int index = path.indexOf('/');
if (index == -1) return dartLibraries[path];
String libraryName = path.substring(0, index);
String relativePath = path.substring(index + 1);
Uri libraryFileUri = dartLibraries[libraryName];
return libraryFileUri?.resolve(relativePath);
}
/// Return the file URI that corresponds to the given `package` URI, or
/// `null` if the `package` [uri] format is invalid, or there is no
/// corresponding package registered.
Uri _translatePackageUri(Uri uri) {
try {
// TODO(sigmund): once we remove the `parse` API, we can ensure that
// packages will never be null and get rid of `?` below.
return packages?.resolve(uri, notFound: _packageUriNotFound);
} on ArgumentError catch (e) {
// TODO(sigmund): catch a more precise error when
// https://github.com/dart-lang/package_config/issues/40 is fixed.
CompilerContext.current.reportWithoutLocation(
templateInvalidPackageUri.withArguments(uri, '$e'), Severity.error);
return null;
}
}
static Uri _packageUriNotFound(Uri uri) {
String name = uri.pathSegments.first;
CompilerContext.current.reportWithoutLocation(
templatePackageNotFound.withArguments(name, uri), Severity.error);
// TODO(sigmund, ahe): ensure we only report an error once,
// this null result will likely cause another error further down in the
// compiler.
return null;
}
static Future<UriTranslator> parse(FileSystem fileSystem, Uri sdk,
{Uri packages}) async {
Uri librariesJson = sdk?.resolve("lib/libraries.json");
// TODO(ahe): Provide a value for this file.
Uri patches = null;
packages ??= Uri.base.resolve(".packages");
List<int> bytes;
try {
bytes = await fileSystem.entityForUri(packages).readAsBytes();
} on FileSystemException catch (e) {
deprecated_inputError(packages, -1, e.message);
}
Packages parsedPackages;
try {
parsedPackages = new MapPackages(packages_file.parse(bytes, packages));
} on FormatException catch (e) {
return deprecated_inputError(packages, e.offset, e.message);
}
var dartLibraries = await computeDartLibraries(fileSystem, librariesJson);
return new UriTranslatorImpl(dartLibraries,
await computeDartPatches(fileSystem, patches), parsedPackages);
}
}