fix(linter/eslint/prefer-exponentiation-operator): preserve autofix precedence (#27150)

Fixes #27149

The safe fixer previously changed `Math.pow(a, b).toFixed(2)` to `a ** b.toFixed(2)`, changing which value receives the method call. Parenthesize the replacement when the call is used as a member object, callee, tagged template tag, TypeScript non-null operand, or TypeScript instantiation operand. Regression cases cover the reported forms and contexts where parentheses are unnecessary.
This commit is contained in:
camc314 committed 2026-09-28 16:01:50 +00:00
1 parent 18d59b7713
commit f08236b729
2 files changed
+106

No files matched your search

@@ -175,6 +175,13 @@ fn needs_parens_for_parent(node: &AstNode, ctx: &LintContext) -> bool {
| AstKind::AwaitExpression(_)
| AstKind::TSAsExpression(_)
| AstKind::TSSatisfiesExpression(_) => true,
AstKind::StaticMemberExpression(_)
| AstKind::ComputedMemberExpression(_)
| AstKind::PrivateFieldExpression(_)
| AstKind::CallExpression(_)
| AstKind::TaggedTemplateExpression(_)
| AstKind::TSNonNullExpression(_)
| AstKind::TSInstantiationExpression(_) => parent.span().start == node.span().start,
_ => false,
}
}
@@ -223,6 +230,17 @@ fn test() {
"Math.pow(a, b) as any",
// With comments - no fix should be applied
"Math.pow(a, b) + Math.pow(c, /* comment */ d)",
"Math.pow(a, b).toFixed(2)",
"Math.pow(a, b)?.toFixed(2)",
"Math.pow(a, b)[0]",
"Math.pow(a, b)()",
"Math.pow(a, b)`x`",
"Math.pow(a, b)!",
"object[Math.pow(a, b)]",
"fn(Math.pow(a, b))",
"(Math.pow(a, b)).toFixed(2)",
"Math.pow(a, b)<T>()",
"Math.pow(a, b)<T>",
];
let fix = vec![
@@ -261,6 +279,17 @@ fn test() {
("Math.pow(a.b, c.d)", "a.b ** c.d"),
// Call expressions don't need parens
("Math.pow(f(), g())", "f() ** g()"),
("Math.pow(a, b).toFixed(2)", "(a ** b).toFixed(2)"),
("Math.pow(a, b)?.toFixed(2)", "(a ** b)?.toFixed(2)"),
("Math.pow(a, b)[0]", "(a ** b)[0]"),
("Math.pow(a, b)()", "(a ** b)()"),
("Math.pow(a, b)`x`", "(a ** b)`x`"),
("Math.pow(a, b)!", "(a ** b)!"),
("object[Math.pow(a, b)]", "object[a ** b]"),
("fn(Math.pow(a, b))", "fn(a ** b)"),
("(Math.pow(a, b)).toFixed(2)", "(a ** b).toFixed(2)"),
("Math.pow(a, b)<T>()", "(a ** b)<T>()"),
("Math.pow(a, b)<T>", "(a ** b)<T>"),
];
Tester::new(
@@ -100,3 +100,80 @@ source: crates/oxc_linter/src/tester.rs
· ────────────────────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b).toFixed(2)
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)?.toFixed(2)
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)[0]
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)()
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)`x`
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)!
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:8]
1 │ object[Math.pow(a, b)]
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:4]
1 │ fn(Math.pow(a, b))
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:2]
1 │ (Math.pow(a, b)).toFixed(2)
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)<T>()
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.
⚠ eslint(prefer-exponentiation-operator): Prefer `**` over `Math.pow`.
╭─[prefer_exponentiation_operator.tsx:1:1]
1 │ Math.pow(a, b)<T>
· ──────────────
╰────
help: Replace `Math.pow(a, b)` with `a ** b`.