mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): eslint-plugin-jest: no-deprecated-function (#1316)
This commit is contained in:
parent
8cb0795796
commit
3df810bf51
3 changed files with 239 additions and 0 deletions
|
|
@ -113,6 +113,7 @@ mod jest {
|
|||
pub mod no_commented_out_tests;
|
||||
pub mod no_conditional_expect;
|
||||
pub mod no_confusing_set_timeout;
|
||||
pub mod no_deprecated_functions;
|
||||
pub mod no_disabled_tests;
|
||||
pub mod no_done_callback;
|
||||
pub mod no_export;
|
||||
|
|
@ -285,6 +286,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
jest::no_commented_out_tests,
|
||||
jest::no_conditional_expect,
|
||||
jest::no_confusing_set_timeout,
|
||||
jest::no_deprecated_functions,
|
||||
jest::no_disabled_tests,
|
||||
jest::no_done_callback,
|
||||
jest::no_export,
|
||||
|
|
|
|||
182
crates/oxc_linter/src/rules/jest/no_deprecated_functions.rs
Normal file
182
crates/oxc_linter/src/rules/jest/no_deprecated_functions.rs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
use oxc_ast::{ast::Expression, AstKind};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
use phf::{phf_map, Map};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::{context::LintContext, fixer::Fix, rule::Rule};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions")]
|
||||
#[diagnostic(severity(warning), help("{0:?} has been deprecated in favor of {1:?}"))]
|
||||
pub struct DeprecatedFunction(pub String, pub String, #[label] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct JestConfig {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoDeprecatedFunctions {
|
||||
pub jest: JestConfig,
|
||||
}
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
/// Over the years Jest has accrued some debt in the form of functions that have
|
||||
/// either been renamed for clarity, or replaced with more powerful APIs.
|
||||
///
|
||||
/// This rule can also autofix a number of these deprecations for you.
|
||||
/// #### `jest.resetModuleRegistry`
|
||||
/// This function was renamed to `resetModules` in Jest 15 and removed in Jest 27.
|
||||
///
|
||||
/// #### `jest.addMatchers`
|
||||
/// This function was replaced with `expect.extend` in Jest 17 and removed in Jest 27.
|
||||
///
|
||||
/// #### `require.requireActual` & `require.requireMock`
|
||||
/// These functions were replaced in Jest 21 and removed in Jest 26.
|
||||
///
|
||||
/// Originally, the `requireActual` & `requireMock` the `requireActual`&
|
||||
/// `requireMock` functions were placed onto the `require` function.
|
||||
///
|
||||
/// These functions were later moved onto the `jest` object in order to be easier
|
||||
/// for type checkers to handle, and their use via `require` deprecated. Finally,
|
||||
/// the release of Jest 26 saw them removed from the `require` function altogether.
|
||||
///
|
||||
/// #### `jest.runTimersToTime`
|
||||
/// This function was renamed to `advanceTimersByTime` in Jest 22 and removed in Jest 27.
|
||||
///
|
||||
/// #### `jest.genMockFromModule`
|
||||
/// This function was renamed to `createMockFromModule` in Jest 26, and is scheduled for removal in Jest 30.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// While typically these deprecated functions are kept in the codebase for a number
|
||||
/// of majors, eventually they are removed completely.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// jest.resetModuleRegistry // since Jest 15
|
||||
/// jest.addMatchers // since Jest 17
|
||||
/// ```
|
||||
NoDeprecatedFunctions,
|
||||
style,
|
||||
);
|
||||
|
||||
const DEPRECATED_FUNCTIONS_MAP: Map<&'static str, (usize, &'static str)> = phf_map! {
|
||||
"jest.resetModuleRegistry" => (15, "jest.resetModules"),
|
||||
"jest.addMatchers" => (17, "expect.extend"),
|
||||
"require.requireMock" => (21, "jest.requireMock"),
|
||||
"require.requireActual" => (21, "jest.requireMock"),
|
||||
"jest.runTimersToTime" => (22, "jest.advanceTimersByTime"),
|
||||
"jest.genMockFromModule" => (26, "jest.createMockFromModule"),
|
||||
};
|
||||
|
||||
impl Rule for NoDeprecatedFunctions {
|
||||
fn from_configuration(value: serde_json::Value) -> Self {
|
||||
let version = value
|
||||
.get(0)
|
||||
.and_then(|v| v.get("jest"))
|
||||
.and_then(|v| v.get("version"))
|
||||
.and_then(|v| serde_json::Value::as_str(v))
|
||||
// Todo: Fixed Me
|
||||
// Currently set the default version to the (maybe) latest, to help to find more problems in
|
||||
// the codebase. In the future, the version should come from the cli option or the config files,
|
||||
// such as `package.json` or `eslint.config.js`.
|
||||
.unwrap_or("29");
|
||||
|
||||
let major: Vec<&str> = version.split('.').collect();
|
||||
|
||||
Self { jest: JestConfig { version: major[0].to_string() } }
|
||||
}
|
||||
|
||||
fn run<'a>(&self, node: &oxc_semantic::AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let AstKind::MemberExpression(mem_expr) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
let mut chain: Vec<Cow<'a, str>> = Vec::new();
|
||||
if let Expression::Identifier(ident) = mem_expr.object() {
|
||||
chain.push(Cow::Borrowed(ident.name.as_str()));
|
||||
}
|
||||
|
||||
if let Some(name) = mem_expr.static_property_name() {
|
||||
chain.push(Cow::Borrowed(name));
|
||||
}
|
||||
|
||||
let node_name = chain.join(".");
|
||||
// Todo: read from configuration
|
||||
let jest_version_num: usize = self.jest.version.parse().unwrap_or(29);
|
||||
|
||||
if let Some((base_version, replacement)) = DEPRECATED_FUNCTIONS_MAP.get(&node_name) {
|
||||
if jest_version_num >= *base_version {
|
||||
ctx.diagnostic_with_fix(
|
||||
DeprecatedFunction(node_name, (*replacement).to_string(), mem_expr.span()),
|
||||
|| Fix::new(*replacement, mem_expr.span()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tests() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("jest", Some(serde_json::json!([{ "jest": { "version": "14" } }]))),
|
||||
("require('fs')", Some(serde_json::json!([{ "jest": { "version": "14" } }]))),
|
||||
("jest.resetModuleRegistry", Some(serde_json::json!([{ "jest": { "version": "14" } }]))),
|
||||
("require.requireActual", Some(serde_json::json!([{ "jest": { "version": "17" } }]))),
|
||||
("jest.genMockFromModule", Some(serde_json::json!([{ "jest": { "version": "25" } }]))),
|
||||
("jest.genMockFromModule", Some(serde_json::json!([{ "jest": { "version": "25.1.1" } }]))),
|
||||
("require.requireActual", Some(serde_json::json!([{ "jest": { "version": "17.2" } }]))),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("jest.resetModuleRegistry", None),
|
||||
// replace with `jest.resetModules` in Jest 15
|
||||
("jest.resetModuleRegistry", Some(serde_json::json!([{ "jest": { "version": "16" }}]))),
|
||||
// replace with `jest.requireMock` in Jest 17.
|
||||
("jest.addMatchers", Some(serde_json::json!([{ "jest": { "version": "18" }}]))),
|
||||
// replace with `jest.requireMock` in Jest 21.
|
||||
("require.requireMock", Some(serde_json::json!([{ "jest": { "version": "22" }}]))),
|
||||
// replace with `jest.requireActual` in Jest 21.
|
||||
("require.requireActual", Some(serde_json::json!([{ "jest": { "version": "22" }}]))),
|
||||
// replace with `jest.advanceTimersByTime` in Jest 22
|
||||
("jest.runTimersToTime", Some(serde_json::json!([{ "jest": { "version": "23" }}]))),
|
||||
// replace with `jest.createMockFromModule` in Jest 26
|
||||
("jest.genMockFromModule", Some(serde_json::json!([{ "jest": { "version": "27" }}]))),
|
||||
];
|
||||
|
||||
let fix = vec![
|
||||
(
|
||||
"jest.resetModuleRegistry()",
|
||||
"jest.resetModules()",
|
||||
Some(serde_json::json!([{ "jest": { "version": "21" } }])),
|
||||
),
|
||||
(
|
||||
"jest.addMatchers",
|
||||
"expect.extend",
|
||||
Some(serde_json::json!([{ "jest": { "version": "24" } }])),
|
||||
),
|
||||
(
|
||||
"jest.genMockFromModule",
|
||||
"jest.createMockFromModule",
|
||||
Some(serde_json::json!([{ "jest": { "version": "26" } }])),
|
||||
),
|
||||
(
|
||||
"jest.genMockFromModule",
|
||||
"jest.createMockFromModule",
|
||||
Some(serde_json::json!([{ "jest": { "version": "26.0.0-next.11" } }])),
|
||||
),
|
||||
];
|
||||
|
||||
Tester::new(NoDeprecatedFunctions::NAME, pass, fail)
|
||||
.with_jest_plugin(true)
|
||||
.expect_fix(fix)
|
||||
.test_and_snapshot();
|
||||
}
|
||||
55
crates/oxc_linter/src/snapshots/no_deprecated_functions.snap
Normal file
55
crates/oxc_linter/src/snapshots/no_deprecated_functions.snap
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
assertion_line: 119
|
||||
expression: no_deprecated_functions
|
||||
---
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ jest.resetModuleRegistry
|
||||
· ────────────────────────
|
||||
╰────
|
||||
help: "jest.resetModuleRegistry" has been deprecated in favor of "jest.resetModules"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ jest.resetModuleRegistry
|
||||
· ────────────────────────
|
||||
╰────
|
||||
help: "jest.resetModuleRegistry" has been deprecated in favor of "jest.resetModules"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ jest.addMatchers
|
||||
· ────────────────
|
||||
╰────
|
||||
help: "jest.addMatchers" has been deprecated in favor of "expect.extend"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ require.requireMock
|
||||
· ───────────────────
|
||||
╰────
|
||||
help: "require.requireMock" has been deprecated in favor of "jest.requireMock"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ require.requireActual
|
||||
· ─────────────────────
|
||||
╰────
|
||||
help: "require.requireActual" has been deprecated in favor of "jest.requireMock"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ jest.runTimersToTime
|
||||
· ────────────────────
|
||||
╰────
|
||||
help: "jest.runTimersToTime" has been deprecated in favor of "jest.advanceTimersByTime"
|
||||
|
||||
⚠ eslint-plugin-jest(no-deprecated-functions): Disallow use of deprecated functions
|
||||
╭─[no_deprecated_functions.tsx:1:1]
|
||||
1 │ jest.genMockFromModule
|
||||
· ──────────────────────
|
||||
╰────
|
||||
help: "jest.genMockFromModule" has been deprecated in favor of "jest.createMockFromModule"
|
||||
|
||||
|
||||
Loading…
Reference in a new issue