| Index: pkg/analyzer/lib/src/lint/project.dart
|
| diff --git a/pkg/analyzer/lib/src/lint/project.dart b/pkg/analyzer/lib/src/lint/project.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9b22294e15c0a400b850869021a265ce31685fb6
|
| --- /dev/null
|
| +++ b/pkg/analyzer/lib/src/lint/project.dart
|
| @@ -0,0 +1,129 @@
|
| +// 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.
|
| +
|
| +import 'dart:io';
|
| +
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/resolver.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/lint/io.dart';
|
| +import 'package:analyzer/src/lint/pub.dart';
|
| +import 'package:path/path.dart' as p;
|
| +
|
| +Pubspec _findAndParsePubspec(Directory root) {
|
| + if (root.existsSync()) {
|
| + File pubspec = root
|
| + .listSync(followLinks: false)
|
| + .firstWhere((f) => isPubspecFile(f), orElse: () => null);
|
| + if (pubspec != null) {
|
| + return new Pubspec.parse(pubspec.readAsStringSync(),
|
| + sourceUrl: p.toUri(pubspec.path));
|
| + }
|
| + }
|
| + return null;
|
| +}
|
| +
|
| +/// A semantic representation of a Dart project.
|
| +///
|
| +/// Projects provide a semantic model of a Dart project based on the
|
| +/// [pub package layout conventions](https://www.dartlang.org/tools/pub/package-layout.html).
|
| +/// This model allows clients to traverse project contents in a convenient and
|
| +/// standardized way, access global information (such as whether elements are
|
| +/// in the "public API") and resources that have special meanings in the
|
| +/// context of pub package layout conventions.
|
| +class DartProject {
|
| + _ApiModel _apiModel;
|
| + String _name;
|
| + Pubspec _pubspec;
|
| +
|
| + /// Project root.
|
| + final Directory root;
|
| +
|
| + /// Create a Dart project for the corresponding [context] and [sources].
|
| + /// If a [dir] is unspecified the current working directory will be
|
| + /// used.
|
| + DartProject(AnalysisContext context, List<Source> sources, {Directory dir})
|
| + : root = dir ?? Directory.current {
|
| + _pubspec = _findAndParsePubspec(root);
|
| + _apiModel = new _ApiModel(context, sources, root);
|
| + }
|
| +
|
| + /// The project's name.
|
| + ///
|
| + /// Project names correspond to the package name as specified in the project's
|
| + /// [pubspec]. The pubspec is found relative to the project [root]. If no
|
| + /// pubspec can be found, the name defaults to the project root basename.
|
| + String get name => _name ??= _calculateName();
|
| +
|
| + /// The project's pubspec.
|
| + Pubspec get pubspec => _pubspec;
|
| +
|
| + /// Returns `true` if the given element is part of this project's public API.
|
| + ///
|
| + /// Public API elements are defined as all elements that are in the packages's
|
| + /// `lib` directory, *less* those in `lib/src` (which are treated as private
|
| + /// *implementation files*), plus elements having been explicitly exported
|
| + /// via an `export` directive.
|
| + bool isApi(Element element) => _apiModel.contains(element);
|
| +
|
| + String _calculateName() {
|
| + if (pubspec != null) {
|
| + var nameEntry = pubspec.name;
|
| + if (nameEntry != null) {
|
| + return nameEntry.value.text;
|
| + }
|
| + }
|
| + return p.basename(root.path);
|
| + }
|
| +}
|
| +
|
| +/// An object that can be used to visit Dart project structure.
|
| +abstract class ProjectVisitor<T> {
|
| + T visit(DartProject project) => null;
|
| +}
|
| +
|
| +/// Captures the project's API as defined by pub package layout standards.
|
| +class _ApiModel {
|
| + final AnalysisContext context;
|
| + final List<Source> sources;
|
| + final Directory root;
|
| + final Set<LibraryElement> elements = new Set();
|
| +
|
| + _ApiModel(this.context, this.sources, this.root) {
|
| + _calculate();
|
| + }
|
| +
|
| + /// Return `true` if this element is part of the public API for this package.
|
| + bool contains(Element element) {
|
| + while (element != null) {
|
| + if (!element.isPrivate && elements.contains(element)) {
|
| + return true;
|
| + }
|
| + element = element.enclosingElement;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + _calculate() {
|
| + if (sources == null || sources.isEmpty) {
|
| + return;
|
| + }
|
| +
|
| + var libDir = root.path + '/lib';
|
| + var libSrcDir = libDir + '/src';
|
| +
|
| + for (Source source in sources) {
|
| + var path = source.uri.path;
|
| + if (path.startsWith(libDir) && !path.startsWith(libSrcDir)) {
|
| + var library = context.computeLibraryElement(source);
|
| + var namespaceBuilder = new NamespaceBuilder();
|
| + var exports = namespaceBuilder.createExportNamespaceForLibrary(library);
|
| + var public = namespaceBuilder.createPublicNamespaceForLibrary(library);
|
| + elements.addAll(exports.definedNames.values);
|
| + elements.addAll(public.definedNames.values);
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|