-
-
Notifications
You must be signed in to change notification settings - Fork 454
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Typescript ban-tslint-comment
- Loading branch information
1 parent
0be8397
commit e9d0bf4
Showing
3 changed files
with
189 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
use lazy_static::lazy_static; | ||
use oxc_diagnostics::{ | ||
miette::{self, Diagnostic}, | ||
thiserror::{self, Error}, | ||
}; | ||
use oxc_macros::declare_oxc_lint; | ||
use oxc_span::Span; | ||
use regex::Regex; | ||
|
||
use crate::{context::LintContext, fixer::Fix, rule::Rule}; | ||
|
||
#[derive(Debug, Error, Diagnostic)] | ||
#[error("typescript-eslint(ban-tslint-comment): tslint comment detected: \"{0}\"")] | ||
#[diagnostic(severity(warning))] | ||
struct BanTslintCommentDiagnostic(String, #[label] pub Span); | ||
|
||
#[derive(Debug, Default, Clone)] | ||
pub struct BanTslintComment; | ||
|
||
declare_oxc_lint!( | ||
/// ### What it does | ||
/// This rule disallows `tslint:<rule-flag>` comments | ||
/// | ||
/// ### Why is this bad? | ||
/// Useful when migrating from TSLint to ESLint. Once TSLint has been | ||
/// removed, this rule helps locate TSLint annotations | ||
/// | ||
/// ### Example | ||
/// ```javascript | ||
/// // tslint:disable-next-line | ||
/// someCode(); | ||
/// ``` | ||
BanTslintComment, | ||
style | ||
); | ||
|
||
impl Rule for BanTslintComment { | ||
fn run_once(&self, ctx: &LintContext) { | ||
let comments = ctx.semantic().trivias().comments(); | ||
let source_text_len = ctx.semantic().source_text().len(); | ||
|
||
for (start, comment) in comments { | ||
let raw = &ctx.semantic().source_text()[*start as usize..comment.end() as usize]; | ||
|
||
if is_tslint_comment_directive(raw) { | ||
let comment_span = get_full_comment( | ||
source_text_len, | ||
*start, | ||
comment.end(), | ||
comment.is_multi_line(), | ||
); | ||
|
||
ctx.diagnostic_with_fix( | ||
BanTslintCommentDiagnostic(raw.trim().to_string(), comment_span), | ||
|| Fix::delete(comment_span), | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn is_tslint_comment_directive(raw: &str) -> bool { | ||
lazy_static! { | ||
static ref ENABLE_DISABLE_REGEX: Regex = | ||
Regex::new(r"^\s*tslint:(enable|disable)(?:-(line|next-line))?(:|\s|$)").unwrap(); | ||
} | ||
|
||
ENABLE_DISABLE_REGEX.is_match(raw) | ||
} | ||
|
||
fn get_full_comment(source_text_len: usize, start: u32, end: u32, is_multi_line: bool) -> Span { | ||
let comment_start = start - 2; | ||
let mut comment_end = if is_multi_line { end + 2 } else { end }; | ||
|
||
// Take into account new line at the end of the comment | ||
if source_text_len > comment_end as usize { | ||
comment_end += 1; | ||
} | ||
|
||
Span { start: comment_start, end: comment_end } | ||
} | ||
|
||
#[test] | ||
fn test() { | ||
use crate::tester::Tester; | ||
|
||
let pass = vec![ | ||
r"let a: readonly any[] = [];", | ||
r"let a = new Array();", | ||
r"// some other comment", | ||
r"// TODO: this is a comment that mentions tslint", | ||
r"/* another comment that mentions tslint */", | ||
r"someCode(); // This is a comment that just happens to mention tslint", | ||
]; | ||
|
||
let fail = vec![ | ||
r"/* tslint:disable */", | ||
r"/* tslint:enable */", | ||
r"/* tslint:disable:rule1 rule2 rule3... */", | ||
r"/* tslint:enable:rule1 rule2 rule3... */", | ||
r"// tslint:disable-next-line", | ||
r"someCode(); // tslint:disable-line", | ||
r"// tslint:disable-next-line:rule1 rule2 rule3...", | ||
r"const woah = doSomeStuff(); | ||
// tslint:disable-line | ||
console.log(woah); | ||
", | ||
]; | ||
|
||
let fix = vec![ | ||
( | ||
r"const woah = doSomeStuff(); | ||
// tslint:disable-line | ||
console.log(woah);", | ||
r"const woah = doSomeStuff(); | ||
console.log(woah);", | ||
None, | ||
), | ||
( | ||
r"const woah = doSomeStuff(); | ||
/* tslint:disable-line */ | ||
console.log(woah);", | ||
r"const woah = doSomeStuff(); | ||
console.log(woah);", | ||
None, | ||
), | ||
(r"/* tslint:disable-line */", r"", None), | ||
]; | ||
|
||
Tester::new(BanTslintComment::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
source: crates/oxc_linter/src/tester.rs | ||
expression: ban_tslint_comment | ||
--- | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable" | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ /* tslint:disable */ | ||
· ──────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:enable" | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ /* tslint:enable */ | ||
· ─────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable:rule1 rule2 rule3..." | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ /* tslint:disable:rule1 rule2 rule3... */ | ||
· ───────────────────────────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:enable:rule1 rule2 rule3..." | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ /* tslint:enable:rule1 rule2 rule3... */ | ||
· ──────────────────────────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-next-line" | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ // tslint:disable-next-line | ||
· ─────────────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-line" | ||
╭─[ban_tslint_comment.tsx:1:13] | ||
1 │ someCode(); // tslint:disable-line | ||
· ────────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-next-line:rule1 rule2 rule3..." | ||
╭─[ban_tslint_comment.tsx:1:1] | ||
1 │ // tslint:disable-next-line:rule1 rule2 rule3... | ||
· ──────────────────────────────────────────────── | ||
╰──── | ||
|
||
⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-line" | ||
╭─[ban_tslint_comment.tsx:2:9] | ||
1 │ const woah = doSomeStuff(); | ||
2 │ // tslint:disable-line | ||
· ─────────────────────── | ||
3 │ console.log(woah); | ||
4 │ | ||
╰──── | ||
|