Skip to content

Commit

Permalink
Relativize: use ".." paths when relevant
Browse files Browse the repository at this point in the history
  • Loading branch information
Tpt committed Oct 24, 2024
1 parent ffa64fa commit b296eb1
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 9 deletions.
39 changes: 30 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,10 +711,32 @@ impl<T: Deref<Target = str>> Iri<T> {
let number_of_shared_characters = abs_path[..number_of_shared_characters]
.rfind('/')
.map_or(0, |n| n + 1);
return if base_path[number_of_shared_characters..].contains('/')
|| abs_path[number_of_shared_characters..].contains(':')

let mut relative_candidate = String::new();
let count_of_segments_in_base_path_we_want_to_ignore = base_path
[number_of_shared_characters..]
.split('/')
.skip(1)
.count();
let mut relative_extra_chars = 0;
for _ in 0..count_of_segments_in_base_path_we_want_to_ignore {
relative_candidate.push_str("../"); // We move back to parent
relative_extra_chars += 3;
}
if count_of_segments_in_base_path_we_want_to_ignore > 0
&& abs_path.len() == number_of_shared_characters
{
// We output the full path because we have a / or an empty end
// We remove the last "/"
relative_candidate.pop();
relative_extra_chars -= 1;
}
relative_candidate
.push_str(&abs.0[abs.0.positions.authority_end + number_of_shared_characters..]);
return if relative_candidate.len() > abs.0[abs.0.positions.authority_end..].len()
|| relative_candidate.contains(':')
{
// We output the full path because the relative one is longer
// or will be confused with a scheme
if !abs_path.starts_with('/') && !base_path.is_empty() {
// We output the full IRI because we have a path that does not start with /,
// so it can't be considered as absolute
Expand All @@ -733,7 +755,7 @@ impl<T: Deref<Target = str>> Iri<T> {
},
})
}
} else if abs_path[number_of_shared_characters..].is_empty() {
} else if relative_candidate.is_empty() {
// We use "."
Ok(IriRef {
iri: format!(
Expand All @@ -754,17 +776,16 @@ impl<T: Deref<Target = str>> Iri<T> {
},
})
} else {
// We just override the last element
// We use the relative path
Ok(IriRef {
iri: abs.0[abs.0.positions.authority_end + number_of_shared_characters..]
.to_string(),
iri: relative_candidate,
positions: IriElementsPositions {
scheme_end: 0,
authority_end: 0,
path_end: abs.0.positions.path_end
path_end: abs.0.positions.path_end + relative_extra_chars
- abs.0.positions.authority_end
- number_of_shared_characters,
query_end: abs.0.positions.query_end
query_end: abs.0.positions.query_end + relative_extra_chars
- abs.0.positions.authority_end
- number_of_shared_characters,
},
Expand Down
24 changes: 24 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,29 @@ fn test_relativize_iri() {
("x:", "x:?foo", "x:"),
("http://example.com", "http://example.com#foo", ""),
("http://example.com/a/", "http://example.com/a/b", "."),
(
"http://example.com/a/z/e",
"http://example.com/a/b/",
"../z/e",
),
("http://example.com/a/", "http://example.com/a/b/", ".."),
("http://example.com/a/", "http://example.com/a/b/c", ".."),
(
"http://example.com/a/#foo",
"http://example.com/a/b/c",
"..#foo",
),
("http://example.com/a/", "http://example.com/a/b/c", ".."),
(
"http://example.com/a/b/c",
"http://example.com/a/b/c/d",
"../c",
),
(
"http://example.com/a/b/e",
"http://example.com/a/b/c/d",
"../e",
),
];

for (original, base, output) in examples {
Expand All @@ -1068,6 +1091,7 @@ fn test_relativize_iri() {
resolved, original,
"Resolving {actual} against {base} gives {resolved} and not {original}"
);
// TODO: check elements in the relative IRI
}
}

Expand Down

0 comments on commit b296eb1

Please sign in to comment.