// Copyright 2014 The Flutter Authors. 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:meta/meta.dart'; @immutable class Version implements Comparable<Version> { /// Creates a new [Version] object. factory Version(int? major, int? minor, int? patch, {String? text}) { if (text == null) { text = major == null ? '0' : '$major'; if (minor != null) { text = '$text.$minor'; } if (patch != null) { text = '$text.$patch'; } } return Version._(major ?? 0, minor ?? 0, patch ?? 0, text); } /// Public constant constructor when all fields are non-null, without default value fallbacks. const Version.withText(this.major, this.minor, this.patch, this._text); Version._(this.major, this.minor, this.patch, this._text) { if (major < 0) { throw ArgumentError('Major version must be non-negative.'); } if (minor < 0) { throw ArgumentError('Minor version must be non-negative.'); } if (patch < 0) { throw ArgumentError('Patch version must be non-negative.'); } } /// Creates a new [Version] by parsing [text]. static Version? parse(String? text) { final Match? match = versionPattern.firstMatch(text ?? ''); if (match == null) { return null; } try { final int major = int.parse(match[1] ?? '0'); final int minor = int.parse(match[3] ?? '0'); final int patch = int.parse(match[5] ?? '0'); return Version._(major, minor, patch, text ?? ''); } on FormatException { return null; } } /// Returns the primary version out of a list of candidates. /// /// This is the highest-numbered stable version. static Version? primary(List<Version> versions) { Version? primary; for (final Version version in versions) { if (primary == null || (version > primary)) { primary = version; } } return primary; } static Version get unknown => Version(0, 0, 0, text: 'unknown'); /// The major version number: "1" in "1.2.3". final int major; /// The minor version number: "2" in "1.2.3". final int minor; /// The patch version number: "3" in "1.2.3". final int patch; /// The original string representation of the version number. /// /// This preserves textual artifacts like leading zeros that may be left out /// of the parsed version. final String _text; static final RegExp versionPattern = RegExp(r'^(\d+)(\.(\d+)(\.(\d+))?)?'); /// Two [Version]s are equal if their version numbers are. The version text /// is ignored. @override bool operator ==(Object other) { return other is Version && other.major == major && other.minor == minor && other.patch == patch; } @override int get hashCode => Object.hash(major, minor, patch); bool operator <(Version other) => compareTo(other) < 0; bool operator >(Version other) => compareTo(other) > 0; bool operator <=(Version other) => compareTo(other) <= 0; bool operator >=(Version other) => compareTo(other) >= 0; @override int compareTo(Version other) { if (major != other.major) { return major.compareTo(other.major); } if (minor != other.minor) { return minor.compareTo(other.minor); } return patch.compareTo(other.patch); } @override String toString() => _text; }