-
Notifications
You must be signed in to change notification settings - Fork 0
Fix AI Review Findings in PR #229 #231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a13c498
6a0c127
52ffc6c
20ea8af
20d41bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -593,32 +593,63 @@ impl InboundLinkMap { | |||||
| /// Priority 6: boundary-aligned suffix matching in both directions. | ||||||
| /// Requires the boundary to sit on a path separator so that e.g. | ||||||
| /// `foo_vo.rs` does not match `bar_vo.rs`. | ||||||
| /// Picks the longest (most specific) matching key; equal-length keys are | ||||||
| /// broken lexicographically so results are deterministic regardless of | ||||||
| /// HashMap iteration order. Keys are normalized the same way the matcher | ||||||
| /// normalizes them, so `/src/a.rs` and `src/a.rs` score identically. | ||||||
| fn boundary_suffix(&self, path: &str) -> Option<&Vec<String>> { | ||||||
| let clean = path.strip_prefix("./").unwrap_or(path); | ||||||
| let clean = normalize_path(path.strip_prefix("./").unwrap_or(path)); | ||||||
| let mut best: Option<(&Vec<String>, usize, String)> = None; | ||||||
| for (k, v) in &self.mapping { | ||||||
| let k_clean = k.strip_prefix("./").unwrap_or(k); | ||||||
| if k_clean.is_empty() || clean.is_empty() { | ||||||
| let k_norm = normalize_path(k.strip_prefix("./").unwrap_or(k)); | ||||||
| if k_norm.is_empty() || clean.is_empty() { | ||||||
| continue; | ||||||
| } | ||||||
| if boundary_ends_with(k_clean, clean) || boundary_ends_with(clean, k_clean) { | ||||||
| return Some(v); | ||||||
| let matched_len = if boundary_ends_with(k_norm, clean) { | ||||||
| Some(k_norm.len()) | ||||||
| } else if boundary_ends_with(clean, k_norm) { | ||||||
| // Reverse direction: the matching key's length is what makes a | ||||||
| // candidate specific, so score by k_norm.len() here too. | ||||||
| Some(k_norm.len()) | ||||||
| } else { | ||||||
| None | ||||||
| }; | ||||||
| let Some(len) = matched_len else { continue }; | ||||||
| let better = match best { | ||||||
| None => true, | ||||||
| Some((_, best_len, ref best_key)) => { | ||||||
| len > best_len || (len == best_len && k_norm < best_key.as_str()) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Boundary-suffix winner selection can still vary across runs when two mapping keys normalize to the same value. The equal-length tie-break only uses strict Prompt for AI agents |
||||||
| } | ||||||
| }; | ||||||
| if better { | ||||||
| best = Some((v, len, k_norm.to_string())); | ||||||
| } | ||||||
| } | ||||||
| None | ||||||
| best.map(|(v, _, _)| v) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /// Strip leading `./` and `/` so equivalent path forms compare identically. | ||||||
| fn normalize_path(p: &str) -> &str { | ||||||
| p.trim_start_matches("./").trim_start_matches('/') | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Path normalization misses mixed prefixes like Prompt for AI agents
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| /// True when `full` ends with `suffix` and the boundary before the suffix is | ||||||
| /// either the start of the string or a path separator (`/` or `\`). | ||||||
| /// Leading `./` and `/` are stripped from both sides first so a suffix like | ||||||
| /// `/b_vo.rs` is treated the same as `b_vo.rs` (the separator check then | ||||||
| /// applies to the byte just before the matched suffix). | ||||||
| fn boundary_ends_with(full: &str, suffix: &str) -> bool { | ||||||
| let full = full.trim_start_matches("./").trim_start_matches('/'); | ||||||
| let suffix = suffix.trim_start_matches("./").trim_start_matches('/'); | ||||||
| if !full.ends_with(suffix) { | ||||||
| return false; | ||||||
| } | ||||||
| let before = full.len() - suffix.len(); | ||||||
| before == 0 | ||||||
| || full | ||||||
| .as_bytes() | ||||||
| .get(before) | ||||||
| .get(before - 1) | ||||||
| .is_some_and(|b| *b == b'/' || *b == b'\\') | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.