@@ -13,12 +13,15 @@ use oxc_semantic::NodeId;
1313use oxc_span:: { GetSpan , Span } ;
1414use oxc_syntax:: { identifier:: is_identifier_name, keyword:: is_reserved_keyword_or_global_object} ;
1515
16+ use schemars:: JsonSchema ;
17+ use serde:: Deserialize ;
18+
1619use crate :: {
1720 AstNode ,
1821 ast_util:: get_function_name_with_kind,
1922 context:: LintContext ,
2023 fixer:: { RuleFix , RuleFixer } ,
21- rule:: Rule ,
24+ rule:: { Rule , TupleRuleConfig } ,
2225} ;
2326
2427fn named_diagnostic ( function_name : & str , span : Span ) -> OxcDiagnostic {
@@ -33,32 +36,43 @@ fn unnamed_diagnostic(inferred_name_or_description: &str, span: Span) -> OxcDiag
3336 . with_help ( "Consider giving this function expression a name." )
3437}
3538
36- #[ derive( Debug , Clone , Default ) ]
37- struct FuncNamesConfig {
38- functions : FuncNamesConfigType ,
39- generators : FuncNamesConfigType ,
40- }
41-
42- #[ derive( Debug , Default , Clone ) ]
43- pub struct FuncNames {
44- config : FuncNamesConfig ,
45- }
46-
47- #[ derive( Debug , Default , Clone , Copy , PartialEq ) ]
39+ #[ derive( Debug , Default , Clone , Copy , PartialEq , JsonSchema , Deserialize ) ]
40+ #[ serde( rename_all = "kebab-case" ) ]
4841enum FuncNamesConfigType {
42+ /// Requires all function expressions to have a name.
4943 #[ default]
5044 Always ,
45+ /// Requires a name only if one is not automatically inferred.
5146 AsNeeded ,
47+ /// Disallows names for function expressions.
5248 Never ,
5349}
5450
55- impl From < & serde_json:: Value > for FuncNamesConfigType {
56- fn from ( raw : & serde_json:: Value ) -> Self {
57- match raw. as_str ( ) {
58- Some ( "as-needed" ) => Self :: AsNeeded ,
59- Some ( "never" ) => Self :: Never ,
60- _ => Self :: Always ,
61- }
51+ #[ derive( Debug , Default , Clone , JsonSchema , Deserialize ) ]
52+ #[ serde( default ) ]
53+ pub struct FuncNames ( FuncNamesConfigType , FuncNamesGeneratorsConfig ) ;
54+
55+ #[ derive( Debug , Default , Clone , JsonSchema , Deserialize ) ]
56+ #[ serde( rename_all = "camelCase" , default , deny_unknown_fields) ]
57+ pub struct FuncNamesGeneratorsConfig {
58+ /// Configuration for generator function expressions. If not specified, uses the
59+ /// primary configuration.
60+ ///
61+ /// Accepts `always`, `as-needed`, or `never`.
62+ ///
63+ /// Generator functions are those defined using the `function*` syntax.
64+ /// ```js
65+ /// function* foobar(i) {
66+ /// yield i;
67+ /// yield i + 10;
68+ /// }
69+ /// ```
70+ generators : Option < FuncNamesConfigType > ,
71+ }
72+
73+ impl FuncNames {
74+ fn generators_config ( & self ) -> FuncNamesConfigType {
75+ self . 1 . generators . unwrap_or ( self . 0 )
6276 }
6377}
6478
@@ -74,24 +88,6 @@ declare_oxc_lint!(
7488 /// This makes it more difficult to find where an error is thrown.
7589 /// Providing an explicit name also improves readability and consistency.
7690 ///
77- /// ### Options
78- ///
79- /// First option:
80- /// - Type: `string`
81- /// - Default: `"always"`
82- /// - Possible values:
83- /// - `"always"` - requires all function expressions to have a name.
84- /// - `"as-needed"` - requires a name only if one is not automatically inferred.
85- /// - `"never"` - disallows names for function expressions.
86- ///
87- /// Second option:
88- /// - Type: `object`
89- /// - Properties:
90- /// - `generators`: `("always" | "as-needed" | "never")` (default: falls back to first option)
91- /// - `"always"` - require named generator function expressions.
92- /// - `"as-needed"` - require a name only when not inferred.
93- /// - `"never"` - disallow names for generator function expressions.
94- ///
9591 /// Example configuration:
9692 /// ```json
9793 /// {
@@ -221,30 +217,19 @@ declare_oxc_lint!(
221217 FuncNames ,
222218 eslint,
223219 style,
224- conditional_fix_suggestion
220+ conditional_fix_suggestion,
221+ config = FuncNames ,
225222) ;
226223
227224impl Rule for FuncNames {
228225 fn from_configuration ( value : serde_json:: Value ) -> Result < Self , serde_json:: error:: Error > {
229- let Some ( functions_config) = value. get ( 0 ) else {
230- return Ok ( Self :: default ( ) ) ;
231- } ;
232- let generators_config =
233- value. get ( 1 ) . and_then ( |v| v. get ( "generators" ) ) . unwrap_or ( functions_config) ;
234-
235- Ok ( Self {
236- config : FuncNamesConfig {
237- functions : FuncNamesConfigType :: from ( functions_config) ,
238- generators : FuncNamesConfigType :: from ( generators_config) ,
239- } ,
240- } )
226+ serde_json:: from_value :: < TupleRuleConfig < Self > > ( value) . map ( TupleRuleConfig :: into_inner)
241227 }
242228
243229 fn run < ' a > ( & self , node : & AstNode < ' a > , ctx : & LintContext < ' a > ) {
244230 if let AstKind :: Function ( func) = node. kind ( ) {
245231 let parent_node = ctx. nodes ( ) . parent_node ( node. id ( ) ) ;
246- let config =
247- if func. generator { self . config . generators } else { self . config . functions } ;
232+ let config = if func. generator { self . generators_config ( ) } else { self . 0 } ;
248233
249234 if is_invalid_function ( config, func, parent_node) {
250235 // For named functions, check if they're recursive (need their name for recursion)
0 commit comments