1- use oxc_ast:: AstKind ;
1+ use oxc_ast:: { AstKind , ast :: TSType } ;
22use oxc_diagnostics:: OxcDiagnostic ;
33use oxc_macros:: declare_oxc_lint;
44use oxc_span:: Span ;
@@ -20,6 +20,7 @@ pub struct MaxParams(Box<MaxParamsConfig>);
2020#[ derive( Debug , Clone ) ]
2121pub struct MaxParamsConfig {
2222 max : usize ,
23+ count_void_this : bool ,
2324}
2425
2526impl std:: ops:: Deref for MaxParams {
@@ -32,7 +33,7 @@ impl std::ops::Deref for MaxParams {
3233
3334impl Default for MaxParamsConfig {
3435 fn default ( ) -> Self {
35- Self { max : 3 }
36+ Self { max : 3 , count_void_this : false }
3637 }
3738}
3839
@@ -88,6 +89,15 @@ declare_oxc_lint!(
8889 ///
8990 /// For example `{ "max": 4 }` would mean that having a function take four
9091 /// parameters is allowed which overrides the default of three.
92+ ///
93+ /// ### countVoidThis
94+ ///
95+ /// `{ "countVoidThis": boolean }`
96+ ///
97+ /// This option is for counting the `this` parameter if it is of type `void`.
98+ ///
99+ /// For example `{ "countVoidThis": true }` would mean that having a function
100+ /// take a `this` parameter of type `void` is counted towards the maximum number of parameters.
91101 MaxParams ,
92102 eslint,
93103 style
@@ -101,15 +111,19 @@ impl Rule for MaxParams {
101111 . and_then ( serde_json:: Number :: as_u64)
102112 . and_then ( |v| usize:: try_from ( v) . ok ( ) )
103113 {
104- Self ( Box :: new ( MaxParamsConfig { max } ) )
114+ Self ( Box :: new ( MaxParamsConfig { max, count_void_this : false } ) )
105115 } else {
106116 let max = config
107117 . and_then ( |config| config. get ( "max" ) )
108118 . and_then ( Value :: as_number)
109119 . and_then ( serde_json:: Number :: as_u64)
110120 . map_or ( 3 , |v| usize:: try_from ( v) . unwrap_or ( 3 ) ) ;
121+ let count_void_this = config
122+ . and_then ( |config| config. get ( "countVoidThis" ) )
123+ . and_then ( Value :: as_bool)
124+ . unwrap_or ( false ) ;
111125
112- Self ( Box :: new ( MaxParamsConfig { max } ) )
126+ Self ( Box :: new ( MaxParamsConfig { max, count_void_this } ) )
113127 }
114128 }
115129
@@ -119,23 +133,31 @@ impl Rule for MaxParams {
119133 if !function. is_declaration ( ) & !function. is_expression ( ) {
120134 return ;
121135 }
136+ let params = & function. params ;
137+ let mut real_len = params. items . len ( ) ;
138+ if let Some ( this_params) = & function. this_param {
139+ let is_void_this = this_params
140+ . type_annotation
141+ . as_ref ( )
142+ . is_some_and ( |t| matches ! ( t. type_annotation, TSType :: TSVoidKeyword ( _) ) ) ;
143+ if self . count_void_this || !is_void_this {
144+ real_len += 1 ;
145+ }
146+ }
122147
123- if function . params . items . len ( ) > self . max {
148+ if real_len > self . max {
124149 if let Some ( id) = & function. id {
125150 let function_name = id. name . as_str ( ) ;
126151 let error_msg = format ! (
127152 "Function '{}' has too many parameters ({}). Maximum allowed is {}." ,
128- function_name,
129- function. params. items. len( ) ,
130- self . max
153+ function_name, real_len, self . max
131154 ) ;
132155 let span = function. params . span ;
133156 ctx. diagnostic ( max_params_diagnostic ( & error_msg, span) ) ;
134157 } else {
135158 let error_msg = format ! (
136159 "Function has too many parameters ({}). Maximum allowed is {}." ,
137- function. params. items. len( ) ,
138- self . max
160+ real_len, self . max
139161 ) ;
140162 let span = function. params . span ;
141163 ctx. diagnostic ( max_params_diagnostic ( & error_msg, span) ) ;
@@ -168,6 +190,23 @@ fn test() {
168190 ( "var test = (a, b, c) => {};" , Some ( serde_json:: json!( [ 3 ] ) ) ) ,
169191 ( "var test = function test(a, b, c) {};" , Some ( serde_json:: json!( [ 3 ] ) ) ) ,
170192 ( "var test = function(a, b, c) {};" , Some ( serde_json:: json!( [ { "max" : 3 } ] ) ) ) ,
193+ (
194+ "function testD(this: void, a) {}" ,
195+ Some ( serde_json:: json!( [ { "max" : 2 , "countVoidThis" : true } ] ) ) ,
196+ ) ,
197+ (
198+ "function testD(this: void, a, b) {}" ,
199+ Some ( serde_json:: json!( [ { "max" : 2 , "countVoidThis" : false } ] ) ) ,
200+ ) ,
201+ ( "const testE = function (this: void, a) {}" , Some ( serde_json:: json!( [ 1 ] ) ) ) ,
202+ (
203+ "const testE = function (this: void, a) {}" ,
204+ Some ( serde_json:: json!( [ { "max" : 2 , "countVoidThis" : false } ] ) ) ,
205+ ) ,
206+ (
207+ "const testE = function (this: any, a) {}" ,
208+ Some ( serde_json:: json!( [ { "max" : 2 , "countVoidThis" : true } ] ) ) ,
209+ ) ,
171210 ] ;
172211
173212 let fail = vec ! [
@@ -186,6 +225,28 @@ fn test() {
186225 }" ,
187226 Some ( serde_json:: json!( [ { "max" : 2 } ] ) ) ,
188227 ) ,
228+ (
229+ "function testD(this: void, a, b) {}" ,
230+ Some ( serde_json:: json!( [ { "max" : 2 , "countVoidThis" : true } ] ) ) ,
231+ ) ,
232+ (
233+ "
234+ class Foo { method(this: void, a) {} }
235+ " ,
236+ Some ( serde_json:: json!( [ { "max" : 1 , "countVoidThis" : true } ] ) ) ,
237+ ) ,
238+ (
239+ "const testE = function (this: void, a) {}" ,
240+ Some ( serde_json:: json!( [ { "max" : 1 , "countVoidThis" : true } ] ) ) ,
241+ ) ,
242+ (
243+ "const testE = function (this: any, a) {}" ,
244+ Some ( serde_json:: json!( [ { "max" : 1 , "countVoidThis" : true } ] ) ) ,
245+ ) ,
246+ (
247+ "const testE = function (this: any, a) {}" ,
248+ Some ( serde_json:: json!( [ { "max" : 1 , "countVoidThis" : false } ] ) ) ,
249+ ) ,
189250 ] ;
190251
191252 Tester :: new ( MaxParams :: NAME , MaxParams :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
0 commit comments