mirror of https://github.com/astral-sh/ruff
add autofix
This commit is contained in:
parent
a2fcf0eb3f
commit
1047e895c7
|
|
@ -1,10 +1,10 @@
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
|
|
||||||
use crate::Violation;
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::{AlwaysFixableViolation, Edit, Fix};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks that all Django URL route definitions using `django.urls.path()`
|
/// Checks that all Django URL route definitions using `django.urls.path()`
|
||||||
|
|
@ -47,12 +47,16 @@ pub(crate) struct DjangoURLPathWithoutTrailingSlash {
|
||||||
url_pattern: String,
|
url_pattern: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for DjangoURLPathWithoutTrailingSlash {
|
impl AlwaysFixableViolation for DjangoURLPathWithoutTrailingSlash {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let DjangoURLPathWithoutTrailingSlash { url_pattern } = self;
|
let DjangoURLPathWithoutTrailingSlash { url_pattern } = self;
|
||||||
format!("URL route `{url_pattern}` is missing a trailing slash")
|
format!("URL route `{url_pattern}` is missing a trailing slash")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> String {
|
||||||
|
"Add trailing slash".to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DJ014
|
/// DJ014
|
||||||
|
|
@ -94,11 +98,35 @@ pub(crate) fn url_path_without_trailing_slash(checker: &Checker, call: &ast::Exp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report diagnostic for routes without trailing slash
|
// Report diagnostic for routes without trailing slash
|
||||||
checker.report_diagnostic(
|
let mut diagnostic = checker.report_diagnostic(
|
||||||
DjangoURLPathWithoutTrailingSlash {
|
DjangoURLPathWithoutTrailingSlash {
|
||||||
url_pattern: route.to_string(),
|
url_pattern: route.to_string(),
|
||||||
},
|
},
|
||||||
route_arg.range(),
|
route_arg.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Generate fix: add trailing slash to the string content
|
||||||
|
// We need to find the position of the closing quote and insert "/" before it
|
||||||
|
let string_range = route_arg.range();
|
||||||
|
let locator = checker.locator();
|
||||||
|
let string_content = locator.slice(string_range);
|
||||||
|
|
||||||
|
// Find the closing quote(s) by working backwards from the end
|
||||||
|
// Handle both single quotes, double quotes, and their triple variants
|
||||||
|
let quote_len = if string_content.ends_with("'''") || string_content.ends_with("\"\"\"") {
|
||||||
|
3
|
||||||
|
} else if string_content.ends_with('\'') || string_content.ends_with('"') {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
// Shouldn't happen for a valid string literal
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert "/" before the closing quote(s)
|
||||||
|
let insertion_point = string_range.end() - TextSize::new(quote_len);
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
||||||
|
"/".to_string(),
|
||||||
|
insertion_point,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_django/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_django/mod.rs
|
||||||
---
|
---
|
||||||
DJ014 URL route `help` is missing a trailing slash
|
DJ014 [*] URL route `help` is missing a trailing slash
|
||||||
--> DJ014.py:6:10
|
--> DJ014.py:6:10
|
||||||
|
|
|
|
||||||
4 | # Errors - missing trailing slash
|
4 | # Errors - missing trailing slash
|
||||||
|
|
@ -11,8 +11,17 @@ DJ014 URL route `help` is missing a trailing slash
|
||||||
7 | path("about", views.about_view), # DJ014
|
7 | path("about", views.about_view), # DJ014
|
||||||
8 | path("contact", views.contact_view), # DJ014
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
3 |
|
||||||
|
4 | # Errors - missing trailing slash
|
||||||
|
5 | urlpatterns = [
|
||||||
|
- path("help", views.help_view), # DJ014
|
||||||
|
6 + path("help/", views.help_view), # DJ014
|
||||||
|
7 | path("about", views.about_view), # DJ014
|
||||||
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
|
|
||||||
DJ014 URL route `about` is missing a trailing slash
|
DJ014 [*] URL route `about` is missing a trailing slash
|
||||||
--> DJ014.py:7:10
|
--> DJ014.py:7:10
|
||||||
|
|
|
|
||||||
5 | urlpatterns = [
|
5 | urlpatterns = [
|
||||||
|
|
@ -22,8 +31,17 @@ DJ014 URL route `about` is missing a trailing slash
|
||||||
8 | path("contact", views.contact_view), # DJ014
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
9 | path("api/users", views.users_view), # DJ014
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
4 | # Errors - missing trailing slash
|
||||||
|
5 | urlpatterns = [
|
||||||
|
6 | path("help", views.help_view), # DJ014
|
||||||
|
- path("about", views.about_view), # DJ014
|
||||||
|
7 + path("about/", views.about_view), # DJ014
|
||||||
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
|
10 | path("blog/posts", views.posts_view), # DJ014
|
||||||
|
|
||||||
DJ014 URL route `contact` is missing a trailing slash
|
DJ014 [*] URL route `contact` is missing a trailing slash
|
||||||
--> DJ014.py:8:10
|
--> DJ014.py:8:10
|
||||||
|
|
|
|
||||||
6 | path("help", views.help_view), # DJ014
|
6 | path("help", views.help_view), # DJ014
|
||||||
|
|
@ -33,8 +51,17 @@ DJ014 URL route `contact` is missing a trailing slash
|
||||||
9 | path("api/users", views.users_view), # DJ014
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
10 | path("blog/posts", views.posts_view), # DJ014
|
10 | path("blog/posts", views.posts_view), # DJ014
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
5 | urlpatterns = [
|
||||||
|
6 | path("help", views.help_view), # DJ014
|
||||||
|
7 | path("about", views.about_view), # DJ014
|
||||||
|
- path("contact", views.contact_view), # DJ014
|
||||||
|
8 + path("contact/", views.contact_view), # DJ014
|
||||||
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
|
10 | path("blog/posts", views.posts_view), # DJ014
|
||||||
|
11 | ]
|
||||||
|
|
||||||
DJ014 URL route `api/users` is missing a trailing slash
|
DJ014 [*] URL route `api/users` is missing a trailing slash
|
||||||
--> DJ014.py:9:10
|
--> DJ014.py:9:10
|
||||||
|
|
|
|
||||||
7 | path("about", views.about_view), # DJ014
|
7 | path("about", views.about_view), # DJ014
|
||||||
|
|
@ -44,8 +71,17 @@ DJ014 URL route `api/users` is missing a trailing slash
|
||||||
10 | path("blog/posts", views.posts_view), # DJ014
|
10 | path("blog/posts", views.posts_view), # DJ014
|
||||||
11 | ]
|
11 | ]
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
6 | path("help", views.help_view), # DJ014
|
||||||
|
7 | path("about", views.about_view), # DJ014
|
||||||
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
- path("api/users", views.users_view), # DJ014
|
||||||
|
9 + path("api/users/", views.users_view), # DJ014
|
||||||
|
10 | path("blog/posts", views.posts_view), # DJ014
|
||||||
|
11 | ]
|
||||||
|
12 |
|
||||||
|
|
||||||
DJ014 URL route `blog/posts` is missing a trailing slash
|
DJ014 [*] URL route `blog/posts` is missing a trailing slash
|
||||||
--> DJ014.py:10:10
|
--> DJ014.py:10:10
|
||||||
|
|
|
|
||||||
8 | path("contact", views.contact_view), # DJ014
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
|
@ -54,8 +90,17 @@ DJ014 URL route `blog/posts` is missing a trailing slash
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
11 | ]
|
11 | ]
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
7 | path("about", views.about_view), # DJ014
|
||||||
|
8 | path("contact", views.contact_view), # DJ014
|
||||||
|
9 | path("api/users", views.users_view), # DJ014
|
||||||
|
- path("blog/posts", views.posts_view), # DJ014
|
||||||
|
10 + path("blog/posts/", views.posts_view), # DJ014
|
||||||
|
11 | ]
|
||||||
|
12 |
|
||||||
|
13 | # OK - has trailing slash
|
||||||
|
|
||||||
DJ014 URL route `bad` is missing a trailing slash
|
DJ014 [*] URL route `bad` is missing a trailing slash
|
||||||
--> DJ014.py:37:10
|
--> DJ014.py:37:10
|
||||||
|
|
|
|
||||||
35 | urlpatterns_mixed = [
|
35 | urlpatterns_mixed = [
|
||||||
|
|
@ -65,8 +110,17 @@ DJ014 URL route `bad` is missing a trailing slash
|
||||||
38 | path("also-good/", views.also_good_view),
|
38 | path("also-good/", views.also_good_view),
|
||||||
39 | path("also-bad", views.also_bad_view), # DJ014
|
39 | path("also-bad", views.also_bad_view), # DJ014
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
34 | # Mixed cases
|
||||||
|
35 | urlpatterns_mixed = [
|
||||||
|
36 | path("good/", views.good_view),
|
||||||
|
- path("bad", views.bad_view), # DJ014
|
||||||
|
37 + path("bad/", views.bad_view), # DJ014
|
||||||
|
38 | path("also-good/", views.also_good_view),
|
||||||
|
39 | path("also-bad", views.also_bad_view), # DJ014
|
||||||
|
40 | ]
|
||||||
|
|
||||||
DJ014 URL route `also-bad` is missing a trailing slash
|
DJ014 [*] URL route `also-bad` is missing a trailing slash
|
||||||
--> DJ014.py:39:10
|
--> DJ014.py:39:10
|
||||||
|
|
|
|
||||||
37 | path("bad", views.bad_view), # DJ014
|
37 | path("bad", views.bad_view), # DJ014
|
||||||
|
|
@ -75,3 +129,10 @@ DJ014 URL route `also-bad` is missing a trailing slash
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
40 | ]
|
40 | ]
|
||||||
|
|
|
|
||||||
|
help: Add trailing slash
|
||||||
|
36 | path("good/", views.good_view),
|
||||||
|
37 | path("bad", views.bad_view), # DJ014
|
||||||
|
38 | path("also-good/", views.also_good_view),
|
||||||
|
- path("also-bad", views.also_bad_view), # DJ014
|
||||||
|
39 + path("also-bad/", views.also_bad_view), # DJ014
|
||||||
|
40 | ]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue