.context/docs/version-parsing.md
This document provides a detailed technical explanation of the version parsing logic used in FVM's FlutterVersion model.
FVM's version parsing system is designed to handle multiple formats of Flutter versions, including:
The central component of this system is the FlutterVersion.parse factory method, which processes a version string input and returns the appropriate FlutterVersion instance.
The core of the implementation uses a regex pattern to match the expected format:
final pattern = RegExp(r'^(?:(?<fork>[^/]+)/)?(?<version>[^@]+)(?:@(?<channel>\w+))?$');
This pattern breaks down as follows:
(?:(?<fork>[^/]+)/)?: Optional named capture group for fork prefix(?<version>[^@]+): Required named capture group for the version string(?:@(?<channel>\w+))?: Optional named capture group for channel suffixThis approach allows us to handle all version formats in a unified way, extracting the relevant components for further processing.
After extracting the components, the implementation:
A key aspect of the implementation is handling the 'v' prefix in semantic versions:
// Try to parse as semantic version
try {
// Create a version to check for validation only
String checkVersion = versionPart;
if (versionPart.startsWith('v')) {
// Strip 'v' only for validation check
checkVersion = versionPart.substring(1);
}
// Validate it's a proper semver
Version.parse(checkVersion);
// Use the original version string (preserving v if present)
return FlutterVersion.release(versionPart, fork: forkName);
} catch (e) {
// Not a valid semver, treat as git reference
return FlutterVersion.gitReference(versionPart, fork: forkName);
}
This approach:
name property for backward compatibilityThe implementation classifies versions into distinct types:
VersionType.channel: For standard Flutter channelsVersionType.release: For semantic versionsVersionType.unknownRef: For git commits or referencesVersionType.custom: For custom versionsThis classification is used throughout the application to determine how versions should be handled.
Fork support is implemented by:
fork propertyfromFork getter to easily identify forked versionsThe implementation includes proper error handling for:
The implementation also includes a compareTo method that allows for proper sorting of versions:
int compareTo(FlutterVersion other) {
final otherVersion = assignVersionWeight(other.version);
final versionWeight = assignVersionWeight(version);
return compareSemver(versionWeight, otherVersion);
}
This ensures that versions are sorted in a logical manner, with releases properly ordered by version numbers.
The following best practices were applied in this implementation:
Regular Expression for Parsing: Using a regex for pattern matching provides a clean, unified approach to handling various formats.
Separation of Concerns: Each version type is handled by a specific constructor, maintaining clear separation of responsibilities.
Backward Compatibility: The 'v' prefix is preserved in the version name for compatibility with existing code and user expectations.
Immutable Objects: FlutterVersion instances are immutable, making them thread-safe and easier to reason about.
Robust Error Handling: Format exceptions provide clear error messages for invalid inputs.
Clear Type System: The use of enum types makes it easy to identify and handle different version types.
The implementation is thoroughly tested through:
This ensures the parser correctly handles all expected version formats and provides appropriate error messages for invalid inputs.