1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//! # nextver
//!
//! A library for parsing and incrementing arbitrarily-formatted versions.
//!
//! Instead of conforming to a specific versioning scheme, this library allows you to define your
//! own version format, parse version strings against it, and increment versions according to
//! semantic and/or calendar rules.
//!
//! Also comes with a [CLI](#cli).
//!
//! ## Examples
//!
//! *Below, the text in `<` and `>` brackets is a specifier. See what they mean [here](#table).*
//!
//! Quickly get a next version:
//!
//! ```
//! use nextver::prelude::*;
//!
//! let next = Sem::next_version_string(
//! "<MAJOR>.<MINOR>.<PATCH>", // format string
//! "1.2.3", // current version string
//! SemLevel::Minor // the specifier to increment
//! )?;
//! assert_eq!(next, "1.3.0");
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ```
//! use nextver::prelude::*;
//!
//! let date = Date::utc_now(); // assume today is 2024-02-23
//! # let date = Date::explicit(2024, 2, 23)?;
//!
//! let next = CalSem::next_version_string(
//! "<YYYY>.<0M>-<PATCH>", // format string
//! "2023.12-42", // current version string
//! date, // the date to update to
//! CalSemLevel::Patch // the specifier to increment if no calendar update
//! )?;
//! assert_eq!(next, "2024.02-0");
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! Or, break down the steps for reusability and comparisons:
//!
//! ```
//! use nextver::prelude::*;
//!
//! let date = Date::utc_now(); // assume today is 2024-02-23
//! # let date = Date::explicit(2024, 2, 23)?;
//!
//! let format = CalSem::new_format("<YYYY>.<MM>.<PATCH>")?;
//! let cur = format.new_version("2023.12.42")?;
//! let next = cur.next(date, CalSemLevel::Patch)?;
//! assert_eq!(next.to_string(), "2024.2.0");
//! // the next version will be compare as greater than the current
//! assert!(next > cur);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## API Overview
//!
//! nextver is built around three main concepts: Schemes, formats, and versions.
//!
//! - **Schemes** dictate the kinds of values allowed in versions and the rules for incrementing
//! them. (See the [table](#table) below.) They are modeled by the [`Scheme`] trait and
//! implemented by the the following structs:
//!
//! - [`Sem`]: A semantic versioning scheme. It is similar to [SemVer](https://semver.org/).
//! - [`CalSem`]: A calendar-semantic versioning scheme. It is similar to
//! [CalVer](https://calver.org/), but with an explicitly-required semantic part(s).
//! - [`Cal`]: A calendar versioning scheme. Its like [`CalSem`] but without semantic specifiers.
//! (This scheme is less useful in practice because there is no way to increment a version twice
//! within the same period of its least significant specifier.)
//!
//! - **Formats** define the structure of a version string. They are modeled by the [`Format`]
//! struct. They contains a sequence of *specifier* and *literal text* tokens. For example,
//! `<MAJOR>.<MINOR>.<PATCH>` is a format string that can be turned into a [`Format`] object.
//!
//! - **Versions** are like Formats, but with actual values instead of specifiers. They represent a
//! a point in a project's development. These are modeled by the [`Version`] struct. They can be
//! incremented to new versions and compared amongst each other.
//!
//! ## Format String Syntax
//!
//! Use any sequence of *specifiers* (listed below) and *literal text* in a format string.
//! Specifiers are bracketed with `<` and `>`. Literal text is anything else (also see
//! [escaping](#escaping-brackets)).
//!
//! ### Table
//!
//! In the "Example" column below, we reference a major of `1`, minor of `2`, patch of `3` and a
//! date of `2001-02-03` (which is in the 4th week).
//!
//! | Specifier | Example | [`Sem`] | [`CalSem`] | [`Cal`] | [Parse Width](#parse-width) | [Min. Format Width](#minimum-format-width) | Description |
//! |---|---|---|---|---|---|---|---|
//! | `<MAJOR>` | `1` | ✅ | ❌ | ❌ | >=1 | - | The major part of a version |
//! | `<MINOR>` | `2` | ✅ | ✅ | ❌ | >=1 | - | The minor part of a version |
//! | `<PATCH>` | `3` | ✅ | ✅ | ❌ | >=1 | - | The patch part of a version |
//! | `<YYYY>` | `2001` | ❌ | ✅ | ✅ | >=1 | - | Full year, years less than 1 BCE are unsupported ([`0` refers to 1 BCE](https://en.wikipedia.org/wiki/Year_zero)) |
//! | `<YY>` | `1` | ❌ | ✅ | ✅ | >=1 | - | Year minus `2000`. For now, has same effect as `year % 100`, but the year 2100 will be `100`, and so on |
//! | `<0Y>` | `01` | ❌ | ✅ | ✅ | >=2 | 2 | Same as `YY` but zero-padded |
//! | `<MM>` | `1` | ❌ | ✅ | ✅ | 1 or 2 | - | Month of year (`1`–`12`) |
//! | `<0M>` | `01` | ❌ | ✅ | ✅ | 2 | 2 | Same as `MM` but zero-padded |
//! | `<WW>` | `4` | ❌ | ✅ | ✅ | 1 or 2 | - | Week of the year (`0`–`53`), week 1 starts with the first Sunday in that year. |
//! | `<0W>` | `04` | ❌ | ✅ | ✅ | 2 | 2 | Same as `WW` but zero-padded |
//! | `<DD>` | `3` | ❌ | ✅ | ✅ | 1 or 2 | - | Day of the month (`1`–`31`) |
//! | `<0D>` | `03` | ❌ | ✅ | ✅ | 2 | 2 | Same as `DD` but zero-padded |
//!
//! Specifiers are case-sensitive. For example, `<major>` or `<yYyY>` are not a valid specifiers.
//!
//! ### Parse Width
//!
//! The parse width comes into play when reading an existing version string. It is the number of
//! characters a specifier can consume. Some specifiers are flexible in this regard, while others
//! are not. For example, `<YYYY>` can consume 1 to an infinite number of characters, while `<0M>`
//! can only consume 2 characters.
//!
//! When the parse width is variable, the specifier is currently implemented to consume as **few**
//! characters as possible (non-greedy). Therefore, exercise caution when using adjacent specifiers
//! that have this quality. **For an unsurprising parse, use a literal separator between them.**
//!
//! ```
//! use nextver::prelude::*;
//!
//! // Let's say I have a version values of major=111, minor=222, patch=333
//! let (major, minor, patch) = (111, 222, 333);
//!
//! // And, my format string contains no separators between the specifiers
//! let format_str = "<MAJOR><MINOR><PATCH>";
//! let version_str = format!("{}{}{}", major, minor, patch);
//!
//! // There is no clear way to parse this because the starts and ends of specifiers are ambiguous.
//! // So, nextver is going to interpret: major=1, minor=1, patch=1222333, despite our intentions
//! let next_str = Sem::next_version_string(format_str, &version_str, SemLevel::Minor)?;
//!
//! // thus, the next version is: major=1, minor=2, patch=0
//! assert_eq!("120", next_str);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ### Minimum Format Width
//!
//! The format width is the minimum number of characters the specifier value will be formatted to
//! with zero-padding. Values with fewer characters than this number will be zero-padded to meet
//! this width, and values with more characters will be left as-is. (In the table above, a `-` value
//! means no zero padding applied.)
//!
//! Take, for example, the `<0Y>` specifier that has a format width of `2`. Given a year, it may be
//! formatted as follows:
//!
//! - `2001` → `01`, zero-padded to meet the format width
//! - `2010` → `10`, as-is formatting
//! - `2100` → `100`, as-is formatting
//!
//! ### Escaping Brackets
//!
//! If you want to use a literal `<` in your format, escape it as `<<`.
//!
//! `>` must **not** be escaped.
//!
//! ```
//! use nextver::prelude::*;
//!
//! // double `<<` in format string (and single closing `>` because it must not be escaped)
//! let format_str = "<MAJOR>-<<some literal text>";
//! // single `<` in version string
//! let version_str = "1-<some literal text>";
//! let format = Sem::new_format(format_str)?;
//! let version = format.new_version(version_str)?;
//!
//! assert_eq!(&version.to_string(), version_str);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## Prelude
//!
//! nextver provides a prelude module for convenience. It contains everything needed to interact
//! with the library.
//!
//! Use it with:
//!
//! ```
//! use nextver::prelude::*;
//! ```
//!
//! ## CLI
//!
//! This crate provides a CLI that can be used to do some API functions straight from the command
//! line.
//!
//! ### Installation
//!
//! ```sh
//! cargo install nextver
//! ```
//!
//! ### Usage
//!
//! ```sh
//! nextver --help
//! ```
pub use crate;
pub use crate;
pub use crate;
pub use crate;
/// A convenience module appropriate for glob imports (`use nextver::prelude::*;`).