Skip to content

Commit

Permalink
feat: add Typescript ban-tslint-comment (#2371)
Browse files Browse the repository at this point in the history
  • Loading branch information
tudorbarbu authored Feb 13, 2024
1 parent 6a25864 commit 8e0277e
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ mod typescript {
pub mod adjacent_overload_signatures;
pub mod array_type;
pub mod ban_ts_comment;
pub mod ban_tslint_comment;
pub mod ban_types;
pub mod no_duplicate_enum_values;
pub mod no_empty_interface;
Expand Down Expand Up @@ -394,6 +395,7 @@ oxc_macros::declare_all_lint_rules! {
typescript::adjacent_overload_signatures,
typescript::array_type,
typescript::ban_ts_comment,
typescript::ban_tslint_comment,
typescript::ban_types,
typescript::no_duplicate_enum_values,
typescript::no_empty_interface,
Expand Down
131 changes: 131 additions & 0 deletions crates/oxc_linter/src/rules/typescript/ban_tslint_comment.rs
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();
}
56 changes: 56 additions & 0 deletions crates/oxc_linter/src/snapshots/ban_tslint_comment.snap
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]
1someCode(); // 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]
1const woah = doSomeStuff();
2// tslint:disable-line
· ───────────────────────
3console.log(woah);
4
╰────

0 comments on commit 8e0277e

Please sign in to comment.