| 1 | module semver |
| 2 | |
| 3 | // * Private structs and functions. |
| 4 | struct RawVersion { |
| 5 | prerelease string |
| 6 | metadata string |
| 7 | mut: |
| 8 | raw_ints []string |
| 9 | } |
| 10 | |
| 11 | const ver_major = 0 |
| 12 | const ver_minor = 1 |
| 13 | const ver_patch = 2 |
| 14 | const versions = [ver_major, ver_minor, ver_patch] |
| 15 | |
| 16 | // TODO: Rewrite using regexps? |
| 17 | // /(\d+)\.(\d+)\.(\d+)(?:\-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-]+))?/ |
| 18 | fn parse(input string) RawVersion { |
| 19 | mut raw_version := input |
| 20 | mut prerelease := '' |
| 21 | mut metadata := '' |
| 22 | plus_idx := raw_version.last_index_u8(`+`) |
| 23 | if plus_idx > 0 { |
| 24 | metadata = raw_version[(plus_idx + 1)..] |
| 25 | raw_version = raw_version[0..plus_idx] |
| 26 | } |
| 27 | hyphen_idx := raw_version.index_('-') |
| 28 | if hyphen_idx > 0 { |
| 29 | prerelease = raw_version[(hyphen_idx + 1)..] |
| 30 | raw_version = raw_version[0..hyphen_idx] |
| 31 | } |
| 32 | raw_ints := raw_version.split('.') |
| 33 | return RawVersion{ |
| 34 | prerelease: prerelease |
| 35 | metadata: metadata |
| 36 | raw_ints: raw_ints |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | fn (ver RawVersion) is_valid() bool { |
| 41 | if ver.raw_ints.len != 3 { |
| 42 | return false |
| 43 | } |
| 44 | return is_valid_number(ver.raw_ints[ver_major]) && is_valid_number(ver.raw_ints[ver_minor]) |
| 45 | && is_valid_number(ver.raw_ints[ver_patch]) && is_valid_string(ver.prerelease) |
| 46 | && is_valid_string(ver.metadata) |
| 47 | } |
| 48 | |
| 49 | fn (ver RawVersion) is_missing(typ int) bool { |
| 50 | return typ >= ver.raw_ints.len - 1 |
| 51 | } |
| 52 | |
| 53 | fn (raw_ver RawVersion) coerce() !Version { |
| 54 | ver := raw_ver.complete() |
| 55 | if !is_valid_number(ver.raw_ints[ver_major]) { |
| 56 | return error('Invalid major version: ${ver.raw_ints}[ver_major]') |
| 57 | } |
| 58 | return ver.to_version() |
| 59 | } |
| 60 | |
| 61 | fn (raw_ver RawVersion) complete() RawVersion { |
| 62 | mut raw_ints := raw_ver.raw_ints.clone() |
| 63 | for raw_ints.len < 3 { |
| 64 | raw_ints << '0' |
| 65 | } |
| 66 | return RawVersion{ |
| 67 | prerelease: raw_ver.prerelease |
| 68 | metadata: raw_ver.metadata |
| 69 | raw_ints: raw_ints |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | fn (raw_ver RawVersion) validate() ?Version { |
| 74 | if !raw_ver.is_valid() { |
| 75 | return none |
| 76 | } |
| 77 | return raw_ver.to_version() |
| 78 | } |
| 79 | |
| 80 | fn (raw_ver RawVersion) to_version() Version { |
| 81 | return Version{raw_ver.raw_ints[ver_major].int(), raw_ver.raw_ints[ver_minor].int(), raw_ver.raw_ints[ver_patch].int(), raw_ver.prerelease, raw_ver.metadata} |
| 82 | } |
| 83 | |