| // Copyright (c) 2026, 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/hint/sdk_constraint_extractor.dart'; |
| import 'package:pub_semver/pub_semver.dart'; |
| |
| /// Calculates the edit to update the SDK constraint in [pubspecFile] to the |
| /// given [minimumVersion]. |
| /// |
| /// Returns `null` if the constraint cannot be found or is not in a supported |
| /// format. |
| PubspecEdit? computeEdit(File pubspecFile, Version minimumVersion) { |
| var extractor = SdkConstraintExtractor(pubspecFile); |
| return _computeEdit( |
| extractor.constraintText(), |
| extractor.constraintOffset(), |
| minimumVersion, |
| ); |
| } |
| |
| /// Calculates the edit to bump the SDK constraint in [pubspecFile] by 1 |
| /// minor version. |
| /// |
| /// Returns `null` if the constraint cannot be found or is not in a supported |
| /// format. |
| PubspecEdit? computeVersionBumpEdit(File pubspecFile) { |
| var extractor = SdkConstraintExtractor(pubspecFile); |
| var text = extractor.constraintText(); |
| if (text == null) return null; |
| |
| Version? newVersion; |
| try { |
| var constraint = VersionConstraint.parse(text); |
| if (constraint is VersionRange) { |
| var min = constraint.min; |
| if (min != null) { |
| newVersion = Version(min.major, min.minor + 1, 0); |
| } |
| } else if (constraint is Version) { |
| newVersion = Version(constraint.major, constraint.minor + 1, 0); |
| } |
| // TODO(kallentu): Support VersionUnion. |
| // For example (e.g. '>=2.12.0 <3.0.0 || >=3.10.0'). |
| } catch (e) { |
| // Can't parse the version constraint. |
| return null; |
| } |
| |
| if (newVersion == null) return null; |
| |
| return _computeEdit(text, extractor.constraintOffset(), newVersion); |
| } |
| |
| PubspecEdit? _computeEdit(String? text, int offset, Version minimumVersion) { |
| if (text == null || offset < 0) { |
| return null; |
| } |
| |
| var length = text.length; |
| var spaceOffset = text.indexOf(' '); |
| if (spaceOffset >= 0) { |
| length = spaceOffset; |
| } |
| |
| String newText; |
| if (text == 'any') { |
| newText = '^$minimumVersion'; |
| } else if (text.startsWith('^')) { |
| newText = '^$minimumVersion'; |
| } else if (text.startsWith('>=')) { |
| newText = '>=$minimumVersion'; |
| } else if (text.startsWith('>')) { |
| newText = '>=$minimumVersion'; |
| } else { |
| return null; |
| } |
| |
| return PubspecEdit( |
| offset: offset, |
| length: length, |
| replacement: newText, |
| originalConstraint: text, |
| newConstraint: newText, |
| ); |
| } |
| |
| /// The result of computing an edit to a pubspec file's SDK constraint. |
| class PubspecEdit { |
| /// The character offset in the document where the edit should be applied. |
| final int offset; |
| |
| /// The length of the text to be replaced. |
| final int length; |
| |
| /// The text to be inserted at [offset], replacing [length] characters. |
| final String replacement; |
| |
| /// The full original SDK constraint text before the edit is applied. |
| final String originalConstraint; |
| |
| /// The full new SDK constraint text after the edit is applied. |
| final String newConstraint; |
| |
| new({ |
| required this.offset, |
| required this.length, |
| required this.replacement, |
| required this.originalConstraint, |
| required this.newConstraint, |
| }); |
| } |