fix(linter) fix incorrect reporting for no_useless_escape (#1062)

This commit is contained in:
Cameron 2023-10-26 08:40:45 +01:00 committed by GitHub
parent 1b64e48ee1
commit 94d3e28aac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 4 deletions

View file

@ -113,6 +113,7 @@ pub enum AstKind<'a> {
JSXFragment(&'a JSXFragment<'a>),
JSXOpeningElement(&'a JSXOpeningElement<'a>),
JSXElementName(&'a JSXElementName<'a>),
JSXExpressionContainer(&'a JSXExpressionContainer<'a>),
JSXAttributeItem(&'a JSXAttributeItem<'a>),
JSXText(&'a JSXText),
@ -242,6 +243,7 @@ impl<'a> AstKind<'a> {
| Self::JSXFragment(_)
| Self::JSXAttributeItem(_)
| Self::JSXText(_)
| Self::JSXExpressionContainer(_)
)
}
@ -364,6 +366,7 @@ impl<'a> GetSpan for AstKind<'a> {
Self::JSXFragment(x) => x.span,
Self::JSXAttributeItem(x) => x.span(),
Self::JSXText(x) => x.span,
Self::JSXExpressionContainer(x) => x.span,
Self::TSModuleBlock(x) => x.span,
@ -530,6 +533,7 @@ impl<'a> AstKind<'a> {
Self::JSXFragment(_) => "JSXFragment".into(),
Self::JSXAttributeItem(_) => "JSXAttributeItem".into(),
Self::JSXText(_) => "JSXText".into(),
Self::JSXExpressionContainer(_) => "JSXExpressionContainer".into(),
Self::TSModuleBlock(_) => "TSModuleBlock".into(),

View file

@ -1069,7 +1069,10 @@ pub trait Visit<'a>: Sized {
}
fn visit_jsx_expression_container(&mut self, expr: &JSXExpressionContainer<'a>) {
let kind = AstKind::JSXExpressionContainer(self.alloc(expr));
self.enter_node(kind);
self.visit_jsx_expression(&expr.expression);
self.leave_node(kind);
}
fn visit_jsx_expression(&mut self, expr: &JSXExpression<'a>) {

View file

@ -4,6 +4,7 @@ use oxc_diagnostics::{
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNodeId;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule, AstNode};
@ -39,12 +40,14 @@ impl Rule for NoUselessEscape {
{
check(
ctx,
node.id(),
literal.span.start,
&check_regexp(literal.span.source_text(ctx.source_text())),
);
}
AstKind::StringLiteral(literal) => check(
ctx,
node.id(),
literal.span.start,
&check_string(literal.span.source_text(ctx.source_text())),
),
@ -52,6 +55,7 @@ impl Rule for NoUselessEscape {
for template_element in &literal.quasis {
check(
ctx,
node.id(),
template_element.span.start - 1,
&check_template(template_element.span.source_text(ctx.source_text())),
);
@ -62,15 +66,25 @@ impl Rule for NoUselessEscape {
}
}
fn is_within_jsx_attribute_item(id: AstNodeId, ctx: &LintContext) -> bool {
if matches!(ctx.nodes().parent_kind(id), Some(AstKind::JSXAttributeItem(_))) {
return true;
}
false
}
#[allow(clippy::cast_possible_truncation)]
fn check(ctx: &LintContext<'_>, start: u32, offsets: &[usize]) {
fn check(ctx: &LintContext<'_>, node_id: AstNodeId, start: u32, offsets: &[usize]) {
let source_text = ctx.source_text();
for offset in offsets {
let offset = start as usize + offset;
let c = source_text[offset..].chars().next().unwrap();
let offset = offset as u32;
let len = c.len_utf8() as u32;
ctx.diagnostic(NoUselessEscapeDiagnostic(c, Span::new(offset - 1, offset + len)));
if !is_within_jsx_attribute_item(node_id, ctx) {
ctx.diagnostic(NoUselessEscapeDiagnostic(c, Span::new(offset - 1, offset + len)));
}
}
}
@ -230,10 +244,10 @@ fn test() {
"var foo = '\\f';",
"var foo = '\\\n';",
"var foo = '\\\r\n';",
// "<foo attr=\"\\d\"/>",
"<foo attr=\"\\d\"/>",
"<div> Testing: \\ </div>",
"<div> Testing: &#x5C </div>",
// "<foo attr='\\d'></foo>",
"<foo attr='\\d'></foo>",
"<> Testing: \\ </>",
"<> Testing: &#x5C </>",
"var foo = `\\x123`",