| // Copyright (c) 2019, 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 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/context/packages.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/lint/pub.dart'; |
| import 'package:analyzer/src/summary/api_signature.dart'; |
| import 'package:analyzer/src/workspace/simple.dart'; |
| import 'package:analyzer/src/workspace/workspace.dart'; |
| import 'package:meta/meta.dart'; |
| |
| /// Information about a Pub workspace. |
| class PubWorkspace extends SimpleWorkspace { |
| /// The name of the file that identifies the root of the workspace. |
| static const String _pubspecName = 'pubspec.yaml'; |
| |
| /// The singular package in this workspace. |
| /// |
| /// Each Pub workspace is itself one package. |
| late final PubWorkspacePackage _theOnlyPackage; |
| |
| /// The associated pubspec file. |
| final File _pubspecFile; |
| |
| /// The content of the `pubspec.yaml` file. |
| /// We read it once, so that all usages return consistent results. |
| final String? _pubspecContent; |
| |
| PubWorkspace._( |
| ResourceProvider provider, |
| Map<String, List<Folder>> packageMap, |
| String root, |
| File pubspecFile, |
| ) : _pubspecFile = pubspecFile, |
| _pubspecContent = _fileContentOrNull(pubspecFile), |
| super(provider, packageMap, root) { |
| _theOnlyPackage = PubWorkspacePackage(root, this); |
| } |
| |
| @override |
| bool get isConsistentWithFileSystem { |
| return _fileContentOrNull(_pubspecFile) == _pubspecContent; |
| } |
| |
| @internal |
| @override |
| void contributeToResolutionSalt(ApiSignature buffer) { |
| buffer.addString(_pubspecContent ?? ''); |
| } |
| |
| @override |
| WorkspacePackage? findPackageFor(String filePath) { |
| final Folder folder = provider.getFolder(filePath); |
| if (provider.pathContext.isWithin(root, folder.path)) { |
| return _theOnlyPackage; |
| } else { |
| return null; |
| } |
| } |
| |
| /// Find the pub workspace that contains the given [filePath]. |
| static PubWorkspace? find( |
| ResourceProvider provider, |
| Map<String, List<Folder>> packageMap, |
| String filePath, |
| ) { |
| var start = provider.getFolder(filePath); |
| for (var current in start.withAncestors) { |
| var pubspec = current.getChildAssumingFile(_pubspecName); |
| if (pubspec.exists) { |
| var root = current.path; |
| return PubWorkspace._(provider, packageMap, root, pubspec); |
| } |
| } |
| } |
| |
| /// Return the content of the [file], `null` if cannot be read. |
| static String? _fileContentOrNull(File file) { |
| try { |
| return file.readAsStringSync(); |
| } catch (_) {} |
| } |
| } |
| |
| /// Information about a package defined in a [PubWorkspace]. |
| /// |
| /// Separate from [Packages] or package maps, this class is designed to simply |
| /// understand whether arbitrary file paths represent libraries declared within |
| /// a given package in a [PubWorkspace]. |
| class PubWorkspacePackage extends WorkspacePackage { |
| @override |
| final String root; |
| |
| Pubspec? _pubspec; |
| |
| /// A flag to indicate if we've tried to parse the pubspec. |
| bool _parsedPubspec = false; |
| |
| @override |
| final PubWorkspace workspace; |
| |
| PubWorkspacePackage(this.root, this.workspace); |
| |
| /// Get the associated parsed [Pubspec], or `null` if there was an error in |
| /// reading or parsing. |
| Pubspec? get pubspec { |
| if (!_parsedPubspec) { |
| _parsedPubspec = true; |
| final content = workspace._pubspecContent; |
| if (content != null) { |
| _pubspec = Pubspec.parse(content); |
| } |
| } |
| return _pubspec; |
| } |
| |
| @override |
| bool contains(Source source) { |
| var filePath = filePathFromSource(source); |
| if (filePath == null) return false; |
| // There is a 1-1 relationship between [PubWorkspace]s and |
| // [PubWorkspacePackage]s. If a file is in a package's workspace, then it |
| // is in the package as well. |
| return workspace.provider.pathContext.isWithin(root, filePath); |
| } |
| |
| @override |
| Map<String, List<Folder>> packagesAvailableTo(String libraryPath) { |
| // TODO(brianwilkerson) Consider differentiating based on whether the |
| // [libraryPath] is inside the `lib` directory. |
| return workspace.packageMap; |
| } |
| |
| @override |
| |
| /// A Pub package's public API consists of libraries found in the top-level |
| /// "lib" directory, and any subdirectories, excluding the "src" directory |
| /// just inside the top-level "lib" directory. |
| bool sourceIsInPublicApi(Source source) { |
| var filePath = filePathFromSource(source); |
| if (filePath == null) return false; |
| var libFolder = workspace.provider.pathContext.join(root, 'lib'); |
| if (!workspace.provider.pathContext.isWithin(libFolder, filePath)) { |
| return false; |
| } |
| var libSrcFolder = workspace.provider.pathContext.join(root, 'lib', 'src'); |
| return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath); |
| } |
| } |