/
no_unused_modules.rs
112 lines (97 loc) · 3.56 KB
/
no_unused_modules.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use oxc_diagnostics::{
miette::{self, diagnostic, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
#[derive(Debug, Error, Diagnostic)]
enum NoUnusedModulesDiagnostic {
#[error("eslint-plugin-import(no-unused-modules): No exports found")]
#[diagnostic(severity(warning))]
NoExportsFound(#[label] Span),
}
/// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md>
#[derive(Debug, Default, Clone)]
pub struct NoUnusedModules {
missing_exports: bool,
}
declare_oxc_lint!(
/// ### What it does
///
/// Reports:
/// * modules without any exports
/// * individual exports not being statically imported or requireed from other modules in the same project
/// * dynamic imports are supported if argument is a literal string
NoUnusedModules,
nursery
);
impl Rule for NoUnusedModules {
fn from_configuration(value: serde_json::Value) -> Self {
Self {
missing_exports: value
.get("missingExports")
.and_then(serde_json::Value::as_bool)
.unwrap_or(false),
}
}
fn run_once(&self, ctx: &LintContext<'_>) {
let module_record = ctx.semantic().module_record();
if self.missing_exports && module_record.local_export_entries.is_empty() {
ctx.diagnostic(NoUnusedModulesDiagnostic::NoExportsFound(Span::new(0, 0)));
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
use serde_json::json;
let missing_exports_options = json!({
"missingExports": true,
});
let pass = vec![
("export default function noOptions() {}", None),
("export default () => 1", Some(missing_exports_options.clone())),
("const a = 1; export { a }", Some(missing_exports_options.clone())),
("function a() { return true }; export { a }", Some(missing_exports_options.clone())),
("const a = 1; const b = 2; export { a, b }", Some(missing_exports_options.clone())),
("const a = 1; export default a", Some(missing_exports_options.clone())),
("export class Foo {}", Some(missing_exports_options.clone())),
("export const [foobar] = [];", Some(missing_exports_options.clone())),
("export const [foobar] = foobarFactory();", Some(missing_exports_options.clone())),
(
"export default function NewComponent () {
return 'I am new component'
}",
Some(missing_exports_options.clone()),
),
(
"export default function NewComponent () {
return 'I am new component'
}",
Some(missing_exports_options.clone()),
),
];
let fail = vec![
("const a = 1", Some(missing_exports_options.clone())),
("/* const a = 1 */", Some(missing_exports_options.clone())),
];
Tester::new(NoUnusedModules::NAME, pass, fail)
.change_rule_path("missing-exports.js")
.with_import_plugin(true)
.test_and_snapshot();
let unused_exports_options = json!({
"unusedExports": true,
"src": ["./no-unused-modules/**/*.js"],
"ignoreExports": ["./no-unused-modules/*ignored*.js"],
});
let pass = vec![
("export default function noOptions() {}", None),
("export default () => 1", Some(unused_exports_options)),
];
let fail = vec![];
Tester::new(NoUnusedModules::NAME, pass, fail)
.change_rule_path("unused-exports.js")
.with_import_plugin(true)
.test_and_snapshot();
}