You've already forked parse_datetime
mirror of
https://github.com/uutils/parse_datetime.git
synced 2026-06-10 16:13:15 -07:00
use proper error mode in items::parse()
This commit is contained in:
+68
-30
@@ -33,6 +33,7 @@ mod ordinal;
|
||||
mod relative;
|
||||
mod time;
|
||||
mod weekday;
|
||||
|
||||
mod epoch {
|
||||
use winnow::{combinator::preceded, ModalResult, Parser};
|
||||
|
||||
@@ -41,6 +42,7 @@ mod epoch {
|
||||
s(preceded("@", dec_int)).parse_next(input)
|
||||
}
|
||||
}
|
||||
|
||||
mod timezone {
|
||||
use super::time;
|
||||
use winnow::ModalResult;
|
||||
@@ -53,12 +55,11 @@ mod timezone {
|
||||
use chrono::NaiveDate;
|
||||
use chrono::{DateTime, Datelike, FixedOffset, TimeZone, Timelike};
|
||||
|
||||
use winnow::error::{StrContext, StrContextValue};
|
||||
use winnow::{
|
||||
ascii::{digit1, multispace0},
|
||||
combinator::{alt, delimited, not, opt, peek, preceded, repeat, separated, trace},
|
||||
error::{ContextError, ErrMode, ParserError},
|
||||
stream::AsChar,
|
||||
error::{AddContext, ContextError, ErrMode, ParserError, StrContext, StrContextValue},
|
||||
stream::{AsChar, Stream},
|
||||
token::{none_of, one_of, take_while},
|
||||
ModalResult, Parser,
|
||||
};
|
||||
@@ -210,6 +211,14 @@ pub fn parse_one(input: &mut &str) -> ModalResult<Item> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn expect_error(input: &mut &str, reason: &'static str) -> ErrMode<ContextError> {
|
||||
ErrMode::Cut(ContextError::new()).add_context(
|
||||
input,
|
||||
&input.checkpoint(),
|
||||
StrContext::Expected(StrContextValue::Description(reason)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
let mut items = Vec::new();
|
||||
let mut date_seen = false;
|
||||
@@ -223,13 +232,10 @@ pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
match item {
|
||||
Item::DateTime(ref dt) => {
|
||||
if date_seen || time_seen {
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(
|
||||
winnow::error::StrContextValue::Description(
|
||||
"date or time cannot appear more than once",
|
||||
),
|
||||
return Err(expect_error(
|
||||
input,
|
||||
"date or time cannot appear more than once",
|
||||
));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
|
||||
date_seen = true;
|
||||
@@ -240,11 +246,7 @@ pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
}
|
||||
Item::Date(ref d) => {
|
||||
if date_seen {
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"date cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
return Err(expect_error(input, "date cannot appear more than once"));
|
||||
}
|
||||
|
||||
date_seen = true;
|
||||
@@ -252,33 +254,27 @@ pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
year_seen = true;
|
||||
}
|
||||
}
|
||||
Item::Time(_) => {
|
||||
Item::Time(ref t) => {
|
||||
if time_seen {
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"time cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
return Err(expect_error(input, "time cannot appear more than once"));
|
||||
}
|
||||
time_seen = true;
|
||||
if t.offset.is_some() {
|
||||
tz_seen = true;
|
||||
}
|
||||
}
|
||||
Item::Year(_) => {
|
||||
if year_seen {
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"year cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
return Err(expect_error(input, "year cannot appear more than once"));
|
||||
}
|
||||
year_seen = true;
|
||||
}
|
||||
Item::TimeZone(_) => {
|
||||
if tz_seen {
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
return Err(expect_error(
|
||||
input,
|
||||
"timezone cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
));
|
||||
}
|
||||
tz_seen = true;
|
||||
}
|
||||
@@ -293,7 +289,7 @@ pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
|
||||
space.parse_next(input)?;
|
||||
if !input.is_empty() {
|
||||
return Err(ErrMode::Backtrack(ContextError::new()));
|
||||
return Err(expect_error(input, "unexpected input"));
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
@@ -557,4 +553,46 @@ mod tests {
|
||||
test_eq_fmt("%Y-%m-%d %H:%M:%S %:z", "Jul 17 06:14:49 2024 BRT"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid() {
|
||||
let result = parse(&mut "2025-05-19 2024-05-20 06:14:49");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("date or time cannot appear more than once"));
|
||||
|
||||
let result = parse(&mut "2025-05-19 2024-05-20");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("date cannot appear more than once"));
|
||||
|
||||
let result = parse(&mut "06:14:49 06:14:49");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("time cannot appear more than once"));
|
||||
|
||||
let result = parse(&mut "2025-05-19 2024");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("year cannot appear more than once"));
|
||||
|
||||
let result = parse(&mut "2025-05-19 +00:00 +01:00");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("timezone cannot appear more than once"));
|
||||
|
||||
let result = parse(&mut "2025-05-19 abcdef");
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("unexpected input"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user