blob: dcbebba9d90d1b43ff9f772b0aa76200afe02f1d [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:analyzer/analyzer.dart' as analyzer;
import '../base/file_system.dart';
import '../dart/package_map.dart';
class DartDependencySetBuilder {
DartDependencySetBuilder(String mainScriptPath, String packagesFilePath) :
_mainScriptPath = canonicalizePath(mainScriptPath),
_mainScriptUri = fs.path.toUri(mainScriptPath),
_packagesFilePath = canonicalizePath(packagesFilePath);
final String _mainScriptPath;
final String _packagesFilePath;
final Uri _mainScriptUri;
Set<String> build() {
final List<String> dependencies = <String>[_mainScriptPath, _packagesFilePath];
final List<Uri> toProcess = <Uri>[_mainScriptUri];
final PackageMap packageMap = new PackageMap(_packagesFilePath);
while (toProcess.isNotEmpty) {
final Uri currentUri = toProcess.removeLast();
final analyzer.CompilationUnit unit = _parse(currentUri.toFilePath());
for (analyzer.Directive directive in unit.directives) {
if (!(directive is analyzer.UriBasedDirective))
continue;
final analyzer.UriBasedDirective uriBasedDirective = directive;
final String uriAsString = uriBasedDirective.uri.stringValue;
Uri resolvedUri = analyzer.resolveRelativeUri(currentUri, Uri.parse(uriAsString));
if (resolvedUri.scheme.startsWith('dart'))
continue;
if (resolvedUri.scheme == 'package') {
final Uri newResolvedUri = packageMap.uriForPackage(resolvedUri);
if (newResolvedUri == null) {
throw new DartDependencyException(
'The following Dart file:\n'
' ${currentUri.toFilePath()}\n'
'...refers, in an import, to the following library:\n'
' $resolvedUri\n'
'That library is in a package that is not known. Maybe you forgot to '
'mention it in your pubspec.yaml file?'
);
}
resolvedUri = newResolvedUri;
}
final String path = canonicalizePath(resolvedUri.toFilePath());
if (!dependencies.contains(path)) {
if (!fs.isFileSync(path)) {
throw new DartDependencyException(
'The following Dart file:\n'
' ${currentUri.toFilePath()}\n'
'...refers, in an import, to the following library:\n'
' $path\n'
'Unfortunately, that library does not appear to exist on your file system.'
);
}
dependencies.add(path);
toProcess.add(resolvedUri);
}
}
}
return dependencies.toSet();
}
analyzer.CompilationUnit _parse(String path) {
String body;
try {
body = fs.file(path).readAsStringSync();
} on FileSystemException catch (error) {
throw new DartDependencyException(
'Could not read "$path" when determining Dart dependencies.',
error,
);
}
try {
return analyzer.parseDirectives(body, name: path);
} on analyzer.AnalyzerError catch (error) {
throw new DartDependencyException(
'When trying to parse this Dart file to find its dependencies:\n'
' $path\n'
'...the analyzer failed with the following error:\n'
' ${error.toString().trimRight()}',
error,
);
} on analyzer.AnalyzerErrorGroup catch (error) {
throw new DartDependencyException(
'When trying to parse this Dart file to find its dependencies:\n'
' $path\n'
'...the analyzer failed with the following error:\n'
' ${error.toString().trimRight()}',
error,
);
}
}
}
class DartDependencyException implements Exception {
DartDependencyException(this.message, [this.parent]);
final String message;
final Exception parent;
@override
String toString() => message;
}