mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): add eslint(jest/no-mocks-import) (#924)
This commit is contained in:
parent
8867f9ada2
commit
eec9fd433a
3 changed files with 172 additions and 0 deletions
|
|
@ -110,6 +110,7 @@ mod jest {
|
|||
pub mod no_focused_tests;
|
||||
pub mod no_interpolation_in_snapshots;
|
||||
pub mod no_jasmine_globals;
|
||||
pub mod no_mocks_import;
|
||||
pub mod no_test_prefixes;
|
||||
pub mod valid_describe_callback;
|
||||
}
|
||||
|
|
@ -210,6 +211,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
jest::no_done_callback,
|
||||
jest::no_interpolation_in_snapshots,
|
||||
jest::no_jasmine_globals,
|
||||
jest::no_mocks_import,
|
||||
unicorn::no_instanceof_array,
|
||||
unicorn::no_unnecessary_await,
|
||||
unicorn::no_thenable,
|
||||
|
|
|
|||
116
crates/oxc_linter/src/rules/jest/no_mocks_import.rs
Normal file
116
crates/oxc_linter/src/rules/jest/no_mocks_import.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use oxc_ast::{
|
||||
ast::{Argument, Expression},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.")]
|
||||
#[diagnostic(
|
||||
severity(warning),
|
||||
help("Instead use `jest.mock` and import from the original module path.")
|
||||
)]
|
||||
struct NoMocksImportDiagnostic(#[label] pub Span);
|
||||
|
||||
/// <https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-mocks-import.md>
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoMocksImport;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// This rule reports imports from a path containing a __mocks__ component.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// import thing from './__mocks__/index';
|
||||
/// require('./__mocks__/index');
|
||||
/// require('__mocks__');
|
||||
///
|
||||
NoMocksImport,
|
||||
restriction
|
||||
);
|
||||
|
||||
impl Rule for NoMocksImport {
|
||||
fn run_once(&self, ctx: &LintContext) {
|
||||
let module_records = ctx.semantic().module_record();
|
||||
|
||||
for import_entry in &module_records.import_entries {
|
||||
let module_specifier = import_entry.module_request.name().as_str();
|
||||
if contains_mocks_dir(module_specifier) {
|
||||
ctx.diagnostic(NoMocksImportDiagnostic(import_entry.module_request.span()));
|
||||
}
|
||||
}
|
||||
|
||||
let Some(require_reference_ids) = ctx.scopes().root_unresolved_references().get("require")
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
for reference_id in require_reference_ids {
|
||||
let reference = ctx.symbols().get_reference(*reference_id);
|
||||
let Some(parent) = ctx.nodes().parent_node(reference.node_id()) else {
|
||||
return;
|
||||
};
|
||||
let AstKind::CallExpression(call_expr) = parent.kind() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(Argument::Expression(Expression::StringLiteral(string_literal))) =
|
||||
call_expr.arguments.get(0)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if contains_mocks_dir(&string_literal.value) {
|
||||
ctx.diagnostic(NoMocksImportDiagnostic(string_literal.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_mocks_dir(value: &str) -> bool {
|
||||
PathBuf::from(value).components().any(|c| match c {
|
||||
std::path::Component::Normal(p) => p == std::ffi::OsStr::new("__mocks__"),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("import something from 'something'", None),
|
||||
("require('somethingElse')", None),
|
||||
("require('./__mocks__.js')", None),
|
||||
("require('./__mocks__x')", None),
|
||||
("require('./__mocks__x/x')", None),
|
||||
("require('./x__mocks__')", None),
|
||||
("require('./x__mocks__/x')", None),
|
||||
("require()", None),
|
||||
("var path = './__mocks__.js'; require(path)", None),
|
||||
("entirelyDifferent(fn)", None),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("require('./__mocks__')", None),
|
||||
("require('./__mocks__/')", None),
|
||||
("require('./__mocks__/index')", None),
|
||||
("require('__mocks__')", None),
|
||||
("require('__mocks__/')", None),
|
||||
("require('__mocks__/index')", None),
|
||||
("import thing from './__mocks__/index'", None),
|
||||
];
|
||||
|
||||
Tester::new(NoMocksImport::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
54
crates/oxc_linter/src/snapshots/no_mocks_import.snap
Normal file
54
crates/oxc_linter/src/snapshots/no_mocks_import.snap
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: no_mocks_import
|
||||
---
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('./__mocks__')
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('./__mocks__/')
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('./__mocks__/index')
|
||||
· ───────────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('__mocks__')
|
||||
· ───────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('__mocks__/')
|
||||
· ────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ require('__mocks__/index')
|
||||
· ─────────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
⚠ eslint(jest/no-mocks-import): Mocks should not be manually imported from a `__mocks__` directory.
|
||||
╭─[no_mocks_import.tsx:1:1]
|
||||
1 │ import thing from './__mocks__/index'
|
||||
· ───────────────────
|
||||
╰────
|
||||
help: Instead use `jest.mock` and import from the original module path.
|
||||
|
||||
|
||||
Loading…
Reference in a new issue