| // Copyright (c) 2017, 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/src/pubspec/pubspec_validator.dart'; |
| import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; |
| import 'package:analyzer/src/util/file_paths.dart' as file_paths; |
| import 'package:analyzer/src/util/yaml.dart'; |
| import 'package:path/path.dart' as path; |
| import 'package:yaml/yaml.dart'; |
| |
| /// Validate the value of the required `name` field. |
| void dependencyValidator(PubspecValidationContext ctx) { |
| /// Return a map whose keys are the names of declared dependencies and whose |
| /// values are the specifications of those dependencies. The map is extracted |
| /// from the given [contents] using the given [key]. |
| Map<dynamic, YamlNode> getDeclaredDependencies(String key) { |
| var contents = ctx.contents; |
| if (contents is! YamlMap) return {}; |
| var field = contents.nodes[key]; |
| if (field == null || (field is YamlScalar && field.value == null)) { |
| return <String, YamlNode>{}; |
| } else if (field is YamlMap) { |
| return field.nodes; |
| } |
| ctx.reportErrorForNode( |
| field, PubspecWarningCode.DEPENDENCIES_FIELD_NOT_MAP, [key]); |
| return <String, YamlNode>{}; |
| } |
| |
| /// Validate that `path` entries reference valid paths. |
| /// |
| /// Valid paths are directories that: |
| /// |
| /// 1. exist, |
| /// 2. contain a pubspec.yaml file |
| /// |
| /// If [checkForPathAndGitDeps] is true, `git` or `path` dependencies will |
| /// be marked invalid. |
| void validatePathEntries(YamlNode dependency, bool checkForPathAndGitDeps) { |
| if (dependency is! YamlMap) { |
| return; |
| } |
| var pathEntry = ctx.asString(dependency[PubspecField.PATH_FIELD]); |
| if (pathEntry != null) { |
| YamlNode pathKey() => dependency.getKey(PubspecField.PATH_FIELD)!; |
| YamlNode pathValue() => dependency.valueAt(PubspecField.PATH_FIELD)!; |
| |
| if (pathEntry.contains(r'\')) { |
| ctx.reportErrorForNode( |
| pathValue(), PubspecWarningCode.PATH_NOT_POSIX, [pathEntry]); |
| return; |
| } |
| var context = ctx.provider.pathContext; |
| var normalizedPath = context.joinAll(path.posix.split(pathEntry)); |
| var packageRoot = context.dirname(ctx.source.fullName); |
| var dependencyPath = context.join(packageRoot, normalizedPath); |
| dependencyPath = context.absolute(dependencyPath); |
| dependencyPath = context.normalize(dependencyPath); |
| var packageFolder = ctx.provider.getFolder(dependencyPath); |
| if (!packageFolder.exists) { |
| ctx.reportErrorForNode( |
| pathValue(), PubspecWarningCode.PATH_DOES_NOT_EXIST, [pathEntry]); |
| } else { |
| if (!packageFolder.getChild(file_paths.pubspecYaml).exists) { |
| ctx.reportErrorForNode(pathValue(), |
| PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST, [pathEntry]); |
| } |
| } |
| if (checkForPathAndGitDeps) { |
| ctx.reportErrorForNode(pathKey(), PubspecWarningCode.INVALID_DEPENDENCY, |
| [PubspecField.PATH_FIELD]); |
| } |
| } |
| |
| var gitEntry = dependency[PubspecField.GIT_FIELD]; |
| if (gitEntry != null && checkForPathAndGitDeps) { |
| ctx.reportErrorForNode(dependency.getKey(PubspecField.GIT_FIELD)!, |
| PubspecWarningCode.INVALID_DEPENDENCY, [PubspecField.GIT_FIELD]); |
| } |
| } |
| |
| var declaredDependencies = |
| getDeclaredDependencies(PubspecField.DEPENDENCIES_FIELD); |
| var declaredDevDependencies = |
| getDeclaredDependencies(PubspecField.DEV_DEPENDENCIES_FIELD); |
| |
| bool isPublishablePackage = false; |
| var contents = ctx.contents; |
| if (contents is! YamlMap) return; |
| var version = contents[PubspecField.VERSION_FIELD]; |
| if (version != null) { |
| var publishTo = ctx.asString(contents[PubspecField.PUBLISH_TO_FIELD]); |
| if (publishTo != 'none') { |
| isPublishablePackage = true; |
| } |
| } |
| |
| for (var dependency in declaredDependencies.entries) { |
| validatePathEntries(dependency.value, isPublishablePackage); |
| } |
| |
| for (var dependency in declaredDevDependencies.entries) { |
| var packageName = dependency.key as YamlNode; |
| if (declaredDependencies.containsKey(packageName)) { |
| ctx.reportErrorForNode( |
| packageName, |
| PubspecWarningCode.UNNECESSARY_DEV_DEPENDENCY, |
| [packageName.valueOrThrow]); |
| } |
| validatePathEntries(dependency.value, false); |
| } |
| } |