forked from oxc-project/oxc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
max_params.rs
143 lines (129 loc) · 4.9 KB
/
max_params.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use oxc_ast::AstKind;
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::{CompactStr, Span};
use serde_json::Value;
use crate::{context::LintContext, rule::Rule, AstNode};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint(max-params): {0:?}")]
#[diagnostic(
severity(warning),
help("This rule enforces a maximum number of parameters allowed in function definitions.")
)]
struct MaxParamsDiagnostic(CompactStr, #[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct MaxParams(Box<MaxParamsConfig>);
#[derive(Debug, Clone)]
pub struct MaxParamsConfig {
max: usize,
}
impl std::ops::Deref for MaxParams {
type Target = MaxParamsConfig;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for MaxParamsConfig {
fn default() -> Self {
Self { max: 3 }
}
}
declare_oxc_lint!(
/// ### What it does
/// Enforce a maximum number of parameters in function definitions
///
/// ### Why is this bad?
/// Functions that take numerous parameters can be difficult to read and write because it requires the memorization of what each parameter is, its type, and the order they should appear in. As a result, many coders adhere to a convention that caps the number of parameters a function can take.
///
/// ### Example
/// ```javascript
/// function foo (bar, baz, qux, qxx) {
/// doSomething();
/// }
/// ```
MaxParams,
style
);
impl Rule for MaxParams {
fn from_configuration(value: Value) -> Self {
let config = value.get(0);
if let Some(max) = config
.and_then(Value::as_number)
.and_then(serde_json::Number::as_u64)
.and_then(|v| usize::try_from(v).ok())
{
Self(Box::new(MaxParamsConfig { max }))
} else {
let max = config
.and_then(|config| config.get("max"))
.and_then(Value::as_number)
.and_then(serde_json::Number::as_u64)
.map_or(3, |v| usize::try_from(v).unwrap_or(3));
Self(Box::new(MaxParamsConfig { max }))
}
}
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::Function(function) => {
if !function.is_declaration() & !function.is_expression() {
return;
}
if function.params.items.len() > self.max {
let error_msg = format!(
"Function has too many parameters ({}). Maximum allowed is {}.",
function.params.items.len(),
self.max
);
let error = CompactStr::from(error_msg);
let span = function.params.span;
ctx.diagnostic(MaxParamsDiagnostic(error, Span::new(span.start, span.end)));
}
}
AstKind::ArrowFunctionExpression(function) => {
if function.params.items.len() > self.max {
let error_msg = format!(
"Function has too many parameters ({}). Maximum allowed is {}.",
function.params.items.len(),
self.max
);
let error = CompactStr::from(error_msg);
let span = function.params.span;
ctx.diagnostic(MaxParamsDiagnostic(error, Span::new(span.start, span.end)));
}
}
_ => {}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
("function test(d, e, f) {}", None),
("var test = function(a, b, c) {};", Some(serde_json::json!([3]))),
("var test = (a, b, c) => {};", Some(serde_json::json!([3]))),
("var test = function test(a, b, c) {};", Some(serde_json::json!([3]))),
("var test = function(a, b, c) {};", Some(serde_json::json!([{ "max": 3 }]))),
];
let fail = vec![
("function test(a, b, c) {}", Some(serde_json::json!([2]))),
("function test(a, b, c, d) {}", None),
("var test = function(a, b, c, d) {};", Some(serde_json::json!([3]))),
("var test = (a, b, c, d) => {};", Some(serde_json::json!([3]))),
("(function(a, b, c, d) {});", Some(serde_json::json!([3]))),
("var test = function test(a, b, c) {};", Some(serde_json::json!([1]))),
("function test(a, b, c) {}", Some(serde_json::json!([{ "max": 2 }]))),
("function test(a, b, c, d) {}", Some(serde_json::json!([{}]))),
("function test(a) {}", Some(serde_json::json!([{ "max": 0 }]))),
(
"function test(a, b, c) {
// Just to make it longer
}",
Some(serde_json::json!([{ "max": 2 }])),
),
];
Tester::new(MaxParams::NAME, pass, fail).test_and_snapshot();
}