| 1 | // * Documentation: https://docs.npmjs.com/misc/semver |
| 2 | module semver |
| 3 | |
| 4 | // * Structures. |
| 5 | // `Version` represents a semantic version in semver format. |
| 6 | pub struct Version { |
| 7 | pub: |
| 8 | major int |
| 9 | minor int |
| 10 | patch int |
| 11 | prerelease string |
| 12 | metadata string |
| 13 | } |
| 14 | |
| 15 | // Increment represents the different types of version increments. |
| 16 | pub enum Increment { |
| 17 | major |
| 18 | minor |
| 19 | patch |
| 20 | } |
| 21 | |
| 22 | struct EmptyInputError { |
| 23 | Error |
| 24 | } |
| 25 | |
| 26 | pub fn (err EmptyInputError) msg() string { |
| 27 | return 'Empty input' |
| 28 | } |
| 29 | |
| 30 | struct InvalidVersionFormatError { |
| 31 | Error |
| 32 | input string |
| 33 | } |
| 34 | |
| 35 | pub fn (err InvalidVersionFormatError) msg() string { |
| 36 | return 'Invalid version format for input "${err.input}"' |
| 37 | } |
| 38 | |
| 39 | // * Constructor. |
| 40 | // from returns a `Version` structure parsed from `input` `string`. |
| 41 | pub fn from(input string) !Version { |
| 42 | if input.len == 0 { |
| 43 | return &EmptyInputError{} |
| 44 | } |
| 45 | raw_version := parse(input) |
| 46 | return raw_version.validate() or { return &InvalidVersionFormatError{ |
| 47 | input: input |
| 48 | } } |
| 49 | } |
| 50 | |
| 51 | // build returns a `Version` structure with given `major`, `minor` and `patch` versions. |
| 52 | pub fn build(major int, minor int, patch int) Version { |
| 53 | // TODO: Check if versions are greater than zero. |
| 54 | return Version{major, minor, patch, '', ''} |
| 55 | } |
| 56 | |
| 57 | // increment returns a `Version` structure with incremented values. |
| 58 | pub fn (ver Version) increment(typ Increment) Version { |
| 59 | return increment_version(ver, typ) |
| 60 | } |
| 61 | |
| 62 | // satisfies returns `true` if the `input` expression can be validated to `true` when run against this `Version`. |
| 63 | // Example: assert semver.build(1,0,0).satisfies('<=2.0.0') |
| 64 | // Example: assert semver.build(1,0,0).satisfies('>=2.0.0') == false |
| 65 | pub fn (ver Version) satisfies(input string) bool { |
| 66 | return version_satisfies(ver, input) |
| 67 | } |
| 68 | |
| 69 | // == checks if `v1` is equal to `v2`. |
| 70 | pub fn (v1 Version) == (v2 Version) bool { |
| 71 | return compare_eq(v1, v2) |
| 72 | } |
| 73 | |
| 74 | // < checks if `v1` is less than `v2`. |
| 75 | pub fn (v1 Version) < (v2 Version) bool { |
| 76 | return compare_lt(v1, v2) |
| 77 | } |
| 78 | |
| 79 | // str returns the `string` representation of the `Version`. |
| 80 | pub fn (ver Version) str() string { |
| 81 | common_string := '${ver.major}.${ver.minor}.${ver.patch}' |
| 82 | |
| 83 | prerelease_string := if ver.prerelease.len > 0 { '-${ver.prerelease}' } else { '' } |
| 84 | metadata_string := if ver.metadata.len > 0 { '+${ver.metadata}' } else { '' } |
| 85 | |
| 86 | return '${common_string}${prerelease_string}${metadata_string}' |
| 87 | } |
| 88 | |
| 89 | // * Utilities. |
| 90 | // coerce converts the `input` version to a `Version` struct. |
| 91 | // coerce will strip any contents *after* the parsed version string: |
| 92 | /* |
| 93 | Example: |
| 94 | import semver |
| 95 | v := semver.coerce('1.3-RC1-b2') or { semver.Version{} } |
| 96 | assert v.satisfies('>1.0 <2.0') == true // 1.3.0 |
| 97 | */ |
| 98 | pub fn coerce(input string) !Version { |
| 99 | return coerce_version(input) |
| 100 | } |
| 101 | |
| 102 | // is_valid returns `true` if the `input` `string` can be converted to |
| 103 | // a (semantic) `Version` struct. |
| 104 | pub fn is_valid(input string) bool { |
| 105 | return is_version_valid(input) |
| 106 | } |
| 107 | |