From ee72fbede9f07dc78035f9fc4bf274d10448f9c8 Mon Sep 17 00:00:00 2001 From: Afloat <132809511+Afloat16@users.noreply.github.com> Date: Tue, 3 Nov 2026 19:46:23 +0700 Subject: [PATCH] Keep non-date paths distinct in HAR API inventories (R3.13) (from #605) --- crates/analysis/src/web_har.rs | 17 ++++++++++++----- .../analysis/tests/regression_har_date_paths.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 crates/analysis/tests/regression_har_date_paths.rs diff --git a/crates/analysis/src/web_har.rs b/crates/analysis/src/web_har.rs index 80b124a4..7f616344 100644 --- a/crates/analysis/src/web_har.rs +++ b/crates/analysis/src/web_har.rs @@ -195,11 +195,18 @@ pub(crate) fn is_uuid(s: &str) -> bool { fn is_iso_date(s: &str) -> bool { let b = s.as_bytes(); - b.len() >= 10 - && b.get(4) == Some(&b'-') - && b.get(7) == Some(&b'-') - && b.iter().take(4).all(u8::is_ascii_digit) - && b.get(5..7).is_some_and(|m| m.iter().all(u8::is_ascii_digit)) + if b.len() != 10 || b.get(4) != Some(&b'-') || b.get(7) != Some(&b'-') { + return false; + } + let number = |start, end| s.get(start..end).filter(|v| v.bytes().all(|b| b.is_ascii_digit())).and_then(|v| v.parse::().ok()); + let (Some(year), Some(month), Some(day)) = (number(0, 4), number(5, 7), number(8, 10)) else { return false }; + let days = match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 => 28 + u32::from(year.is_multiple_of(4) && (!year.is_multiple_of(100) || year.is_multiple_of(400))), + _ => return false, + }; + (1..=days).contains(&day) } /// The outline of a JSON value: types only, never values. diff --git a/crates/analysis/tests/regression_har_date_paths.rs b/crates/analysis/tests/regression_har_date_paths.rs new file mode 100644 index 00000000..50962421 --- /dev/null +++ b/crates/analysis/tests/regression_har_date_paths.rs @@ -0,0 +1,12 @@ +use craft_anything_analysis::web_har::path_template; + +#[test] +fn regression_only_calendar_dates_share_a_date_template() { + for date in ["2024-02-29", "2000-02-29", "2026-11-03", "2026-04-30"] { + assert_eq!(path_template(&format!("/reports/{date}")), "/reports/{date}"); + } + for literal in ["2026-11-news", "2026-11-03-extra", "2026-02-29", "1900-02-29", "2026-13-01", "2026-00-01", "2026-04-31", "2026-01-00"] { + let path = format!("/reports/{literal}"); + assert_eq!(path_template(&path), path); + } +}