feat(resolver): complete query and fragment parsing (#579)

This commit is contained in:
Boshen 2023-07-20 17:48:51 +08:00 committed by GitHub
parent 30b9731843
commit fa20844802
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 14 deletions

View file

@ -51,7 +51,7 @@ Tests ported from [enhanced-resolve](https://github.com/webpack/enhanced-resolve
- ~[ ] forEachBail.test.js~
- [ ] fullSpecified.test.js
- [ ] getPaths.test.js
- [ ] identifier.test.js
- [x] identifier.test.js (see unit test in `crates/oxc_resolver/src/request.rs`)
- [ ] importsField.test.js
- [x] incorrect-description-file.test.js (need to add ctx.fileDependencies)
- [ ] missing.test.js

View file

@ -63,20 +63,20 @@ impl<'a> Request<'a> {
let mut fragment_start: Option<usize> = None;
for (i, c) in request.as_bytes().iter().enumerate().skip(skip) {
match *c {
b'?' => query_start = Some(i),
b'#' => fragment_start = Some(i),
_ => {}
if *c == b'?' {
query_start = Some(i);
}
if *c == b'#' {
fragment_start = Some(i);
break;
}
}
match (query_start, fragment_start) {
(Some(i), Some(j)) if i < j => {
(Some(i), Some(j)) => {
debug_assert!(i < j);
(&request[..i], Some(&request[i..j]), Some(&request[j..]))
}
(Some(i), Some(j)) if i > j => {
(&request[..j], Some(&request[i..]), Some(&request[j..i]))
}
(Some(i), None) => (&request[..i], Some(&request[i..]), None),
(None, Some(j)) => (&request[..j], None, Some(&request[j..])),
_ => (request, None, None),
@ -112,7 +112,7 @@ mod tests {
#[test]
fn relative() -> Result<(), RequestError> {
let requests = ["./test", "../test?#", "../../test?#"];
let requests = ["./test", "../test", "../../test"];
for request in requests {
let mut r = request.to_string();
r.push_str("?#");
@ -163,8 +163,8 @@ mod tests {
("a?#fragment", Some("?"), Some("#fragment")),
("a?query#", Some("?query"), Some("#")),
("a?query#fragment", Some("?query"), Some("#fragment")),
("a#fragment?", Some("?"), Some("#fragment")),
("a#fragment?query", Some("?query"), Some("#fragment")),
("a#fragment?", None, Some("#fragment?")),
("a#fragment?query", None, Some("#fragment?query")),
];
for (request_str, query, fragment) in data {
@ -176,4 +176,52 @@ mod tests {
Ok(())
}
#[test]
// https://github.com/webpack/enhanced-resolve/blob/main/test/identifier.test.js
fn enhanced_resolve_edge_cases() -> Result<(), RequestError> {
let data = [
("path/#", "path/", "", "#"),
("path/as/?", "path/as/", "?", ""),
("path/#/?", "path/", "", "#/?"),
("path/#repo#hash", "path/", "", "#repo#hash"),
("path/#r#hash", "path/", "", "#r#hash"),
("path/#repo/#repo2#hash", "path/", "", "#repo/#repo2#hash"),
("path/#r/#r#hash", "path/", "", "#r/#r#hash"),
("path/#/not/a/hash?not-a-query", "path/", "", "#/not/a/hash?not-a-query"),
];
for (request_str, path, query, fragment) in data {
let request = Request::parse(request_str)?;
assert_eq!(request.path.as_str(), path, "{request_str}");
assert_eq!(request.query.unwrap_or(""), query, "{request_str}");
assert_eq!(request.fragment.unwrap_or(""), fragment, "{request_str}");
}
Ok(())
}
// https://github.com/webpack/enhanced-resolve/blob/main/test/identifier.test.js
#[test]
fn enhanced_resolve_windows_like() -> Result<(), RequestError> {
let data = [
("path\\#", "path\\", "", "#"),
("path\\as\\?", "path\\as\\", "?", ""),
("path\\#\\?", "path\\", "", "#\\?"),
("path\\#repo#hash", "path\\", "", "#repo#hash"),
("path\\#r#hash", "path\\", "", "#r#hash"),
("path\\#repo\\#repo2#hash", "path\\", "", "#repo\\#repo2#hash"),
("path\\#r\\#r#hash", "path\\", "", "#r\\#r#hash"),
("path\\#/not/a/hash?not-a-query", "path\\", "", "#/not/a/hash?not-a-query"),
];
for (request_str, path, query, fragment) in data {
let request = Request::parse(request_str)?;
assert_eq!(request.path.as_str(), path, "{request_str}");
assert_eq!(request.query.unwrap_or(""), query, "{request_str}");
assert_eq!(request.fragment.unwrap_or(""), fragment, "{request_str}");
}
Ok(())
}
}

View file

@ -25,11 +25,11 @@ fn resolve() {
("from nested directory to not overwritten file in module", f.join("multiple_modules"), "m1/b.js", f.join("node_modules/m1/b.js")),
("file with query", f.clone(), "./main1.js?query", f.join("main1.js?query")),
("file with fragment", f.clone(), "./main1.js#fragment", f.join("main1.js#fragment")),
("file with fragment and query", f.clone(), "./main1.js#fragment?query", f.join("main1.js?query#fragment")),
("file with fragment and query", f.clone(), "./main1.js#fragment?query", f.join("main1.js#fragment?query")),
("file with query and fragment", f.clone(), "./main1.js?#fragment", f.join("main1.js?#fragment")),
("file in module with query", f.clone(), "m1/a?query", f.join("node_modules/m1/a.js?query")),
("file in module with fragment", f.clone(), "m1/a#fragment", f.join("node_modules/m1/a.js#fragment")),
("file in module with fragment and query", f.clone(), "m1/a#fragment?query", f.join("node_modules/m1/a.js?query#fragment")),
("file in module with fragment and query", f.clone(), "m1/a#fragment?query", f.join("node_modules/m1/a.js#fragment?query")),
("file in module with query and fragment", f.clone(), "m1/a?#fragment", f.join("node_modules/m1/a.js?#fragment")),
("file in module with query and fragment", f.clone(), "m1/a?#fragment", f.join("node_modules/m1/a.js?#fragment")),
("differ between directory and file, resolve file", f.clone(), "./dirOrFile", f.join("dirOrFile.js")),