| // Copyright (c) 2018, 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:pub_semver/pub_semver.dart'; | |
| import '../exceptions.dart'; | |
| import '../language_version.dart'; | |
| import '../package_name.dart'; | |
| import '../sdk.dart'; | |
| import '../source/sdk.dart'; | |
| import 'incompatibility.dart'; | |
| /// The reason an [Incompatibility]'s terms are incompatible. | |
| sealed class IncompatibilityCause { | |
| const IncompatibilityCause(); | |
| /// Human readable notice / information providing context for this | |
| /// incompatibility. | |
| /// | |
| /// This may be multiple lines, and will be printed before the explanation. | |
| /// This is used highlight information that is useful for understanding the | |
| /// why this conflict happened. | |
| String? get notice => null; | |
| /// Human readable hint indicating how this incompatibility may be resolved. | |
| /// | |
| /// This may be multiple lines, and will be printed after the explanation. | |
| /// This should only be included if it is actionable and likely to resolve the | |
| /// issue for the user. | |
| String? get hint => null; | |
| } | |
| /// The incompatibility represents the requirement that the root package | |
| /// exists. | |
| class RootIncompatibilityCause extends IncompatibilityCause { | |
| factory RootIncompatibilityCause() => const RootIncompatibilityCause._(); | |
| const RootIncompatibilityCause._(); | |
| } | |
| /// The incompatibility represents a package's dependency. | |
| class DependencyIncompatibilityCause extends IncompatibilityCause { | |
| final PackageRange depender; | |
| final PackageRange target; | |
| DependencyIncompatibilityCause(this.depender, this.target); | |
| @override | |
| String? get notice { | |
| final dependerDescription = depender.description; | |
| if (dependerDescription is SdkDescription) { | |
| final targetConstraint = target.constraint; | |
| if (targetConstraint is Version) { | |
| return ''' | |
| Note: ${target.name} is pinned to version $targetConstraint by ${depender.name} from the ${dependerDescription.sdk} SDK. | |
| See https://dart.dev/go/sdk-version-pinning for details. | |
| '''; | |
| } | |
| } | |
| return null; | |
| } | |
| } | |
| /// The incompatibility indicates that the package has no versions that match | |
| /// the given constraint. | |
| class NoVersionsIncompatibilityCause extends IncompatibilityCause { | |
| factory NoVersionsIncompatibilityCause() => | |
| const NoVersionsIncompatibilityCause._(); | |
| const NoVersionsIncompatibilityCause._(); | |
| } | |
| /// The incompatibility indicates that the package has an unknown source. | |
| class UnknownSourceIncompatibilityCause extends IncompatibilityCause { | |
| factory UnknownSourceIncompatibilityCause() => | |
| const UnknownSourceIncompatibilityCause._(); | |
| const UnknownSourceIncompatibilityCause._(); | |
| } | |
| /// The incompatibility was derived from two existing incompatibilities during | |
| /// conflict resolution. | |
| class ConflictCause extends IncompatibilityCause { | |
| /// The incompatibility that was originally found to be in conflict, from | |
| /// which the target incompatibility was derived. | |
| final Incompatibility conflict; | |
| /// The incompatibility that caused the most recent satisfier for [conflict], | |
| /// from which the target incompatibility was derived. | |
| final Incompatibility other; | |
| ConflictCause(this.conflict, this.other); | |
| } | |
| /// The incompatibility represents a package's SDK constraint being | |
| /// incompatible with the current SDK. | |
| class SdkIncompatibilityCause extends IncompatibilityCause { | |
| /// The union of all the incompatible versions' constraints on the SDK. | |
| // TODO(zarah): Investigate if this can be non-nullable | |
| final VersionConstraint? constraint; | |
| /// The SDK with which the package was incompatible. | |
| final Sdk sdk; | |
| bool get noNullSafetyCause => | |
| sdk.isDartSdk && | |
| !LanguageVersion.fromSdkConstraint(constraint).supportsNullSafety && | |
| sdk.version! >= Version(3, 0, 0).firstPreRelease; | |
| @override | |
| String? get notice { | |
| // If the SDK is not available, then we have an actionable [hint] printed | |
| // after the explanation. So we don't need to state that the SDK is not | |
| // available. | |
| if (!sdk.isAvailable) { | |
| return null; | |
| } | |
| // If the SDK is available and we have an incompatibility, then the user has | |
| // the wrong SDK version (one that is not compatible with any solution). | |
| // Thus, it makes sense to highlight the current SDK version. | |
| return 'The current ${sdk.name} SDK version is ${sdk.version}.'; | |
| } | |
| @override | |
| String? get hint { | |
| if (noNullSafetyCause) { | |
| return 'The lower bound of "sdk: \'$constraint\'" must be 2.12.0' | |
| ' or higher to enable null safety.' | |
| '\nFor details, see https://dart.dev/null-safety'; | |
| } | |
| // If the SDK is available, then installing it won't help | |
| if (sdk.isAvailable) { | |
| return null; | |
| } | |
| // Return an install message for the SDK, if there is an install message. | |
| return sdk.installMessage; | |
| } | |
| SdkIncompatibilityCause(this.constraint, this.sdk); | |
| } | |
| /// The incompatibility represents a package that couldn't be found by its | |
| /// source. | |
| class PackageNotFoundIncompatibilityCause extends IncompatibilityCause { | |
| /// The exception indicating why the package couldn't be found. | |
| final PackageNotFoundException exception; | |
| PackageNotFoundIncompatibilityCause(this.exception); | |
| @override | |
| String? get hint => exception.hint; | |
| } | |
| /// The incompatibility represents a package-version that is not allowed to be | |
| /// used in the solve for some external reason. | |
| class PackageVersionForbiddenCause extends IncompatibilityCause { | |
| /// The reason this package version was forbidden. | |
| final String? reason; | |
| PackageVersionForbiddenCause({this.reason}); | |
| @override | |
| String? get hint => reason; | |
| } |