blob: 56c6aab061a6f5b90db9358e3b086815f7c60dde [file] [log] [blame]
library coverage.resolver;
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as p;
/// [Resolver] resolves imports with respect to a given environment.
class Resolver {
static const DART_PREFIX = 'dart:';
static const PACKAGE_PREFIX = 'package:';
static const FILE_PREFIX = 'file://';
final String packageRoot;
final String sdkRoot;
final List<String> failed = [];
Resolver({this.packageRoot, this.sdkRoot});
/// Returns the absolute path wrt. to the given environment or null, if the
/// import could not be resolved.
String resolve(String uri) {
if (uri.startsWith(DART_PREFIX)) {
if (sdkRoot == null) {
// No sdk-root given, do not resolve dart: URIs.
return null;
}
var slashPos = uri.indexOf('/');
var filePath;
if (slashPos != -1) {
var path = uri.substring(DART_PREFIX.length, slashPos);
// Drop patch files, since we don't have their source in the compiled
// SDK.
if (path.endsWith('-patch')) {
failed.add(uri);
return null;
}
// Canonicalize path. For instance: _collection-dev => _collection_dev.
path = path.replaceAll('-', '_');
filePath = '$sdkRoot/${path}${uri.substring(slashPos, uri.length)}';
} else {
// Resolve 'dart:something' to be something/something.dart in the SDK.
var lib = uri.substring(DART_PREFIX.length, uri.length);
filePath = '$sdkRoot/$lib/${lib}.dart';
}
return resolveSymbolicLinks(filePath);
}
if (uri.startsWith(PACKAGE_PREFIX)) {
if (packageRoot == null) {
// No package-root given, do not resolve package: URIs.
return null;
}
var path = uri.substring(PACKAGE_PREFIX.length, uri.length);
return resolveSymbolicLinks(p.join(packageRoot, path));
}
if (uri.startsWith(FILE_PREFIX)) {
return resolveSymbolicLinks(p.fromUri(Uri.parse(uri)));
}
// We cannot deal with anything else.
failed.add(uri);
return null;
}
/// Returns a canonicalized path, or `null` if the path cannot be resolved.
String resolveSymbolicLinks(String path) {
var normalizedPath = p.normalize(path);
var type = FileSystemEntity.typeSync(normalizedPath, followLinks: true);
if (type == FileSystemEntityType.NOT_FOUND) return null;
return new File(normalizedPath).resolveSymbolicLinksSync();
}
}
/// Loads the lines of imported resources.
class Loader {
final List<String> failed = [];
/// Loads an imported resource and returns a [Future] with a [List] of lines.
/// Returns [null] if the resource could not be loaded.
Future<List<String>> load(String path) async {
try {
return new File(path).readAsLines();
} catch (_) {
failed.add(path);
return null;
}
}
}