@@ -3,6 +3,7 @@ use super::{Context, LintRule};
33use crate :: handler:: { Handler , Traverse } ;
44use crate :: swc_util:: StringRepr ;
55
6+ use deno_ast:: view:: { Node , NodeKind , NodeTrait } ;
67use deno_ast:: { view as ast_view, SourceRange , SourceRanged } ;
78use once_cell:: sync:: Lazy ;
89use regex:: { Captures , Regex } ;
@@ -115,6 +116,7 @@ enum IdentToCheck {
115116 key_name : String ,
116117 value_name : Option < String > ,
117118 has_default : bool ,
119+ is_destructuring : bool ,
118120 } ,
119121 /// Local name and imported name in named import, for example:
120122 ///
@@ -177,6 +179,7 @@ impl IdentToCheck {
177179 key_name : & K ,
178180 value_name : Option < & V > ,
179181 has_default : bool ,
182+ is_destructuring : bool ,
180183 ) -> Self
181184 where
182185 K : AsRef < str > ,
@@ -186,6 +189,7 @@ impl IdentToCheck {
186189 key_name : key_name. as_ref ( ) . to_string ( ) ,
187190 value_name : value_name. map ( |v| v. as_ref ( ) . to_string ( ) ) ,
188191 has_default,
192+ is_destructuring,
189193 }
190194 }
191195
@@ -286,12 +290,20 @@ impl IdentToCheck {
286290 key_name,
287291 value_name,
288292 has_default,
293+ is_destructuring : in_var_decl,
289294 } => {
290- if let Some ( value_name) = value_name {
295+ let rename_name = if let Some ( value_name) = value_name {
296+ Some ( value_name)
297+ } else if * in_var_decl {
298+ None
299+ } else {
300+ Some ( key_name)
301+ } ;
302+ if let Some ( name) = rename_name {
291303 return format ! (
292304 "Consider renaming `{}` to `{}`" ,
293- value_name ,
294- to_camelcase( value_name ) ,
305+ name ,
306+ to_camelcase( name ) ,
295307 ) ;
296308 }
297309
@@ -427,6 +439,7 @@ impl CamelcaseHandler {
427439 & key. string_repr ( ) . unwrap_or_else ( || "[KEY]" . to_string ( ) ) ,
428440 Some ( & value_ident. id . inner ) ,
429441 false ,
442+ pat_in_var_declarator ( pat. into ( ) ) ,
430443 ) ,
431444 ) ;
432445 }
@@ -440,6 +453,7 @@ impl CamelcaseHandler {
440453 & key. string_repr ( ) . unwrap_or_else ( || "[KEY]" . to_string ( ) ) ,
441454 Some ( & value_ident. id . inner ) ,
442455 true ,
456+ pat_in_var_declarator ( pat. into ( ) ) ,
443457 ) ,
444458 ) ;
445459 }
@@ -453,14 +467,18 @@ impl CamelcaseHandler {
453467 ..
454468 } ) => {
455469 let has_default = value. is_some ( ) ;
456- self . check_ident (
457- key,
458- IdentToCheck :: object_pat :: < & str , & str > (
459- & key. inner . as_ref ( ) ,
460- None ,
461- has_default,
462- ) ,
463- ) ;
470+ let in_var_declarator = pat_in_var_declarator ( pat. into ( ) ) ;
471+ if !in_var_declarator {
472+ self . check_ident (
473+ key,
474+ IdentToCheck :: object_pat :: < & str , & str > (
475+ & key. inner . as_ref ( ) ,
476+ None ,
477+ has_default,
478+ in_var_declarator,
479+ ) ,
480+ ) ;
481+ }
464482 }
465483 ast_view:: ObjectPatProp :: Rest ( ast_view:: RestPat {
466484 ref arg,
@@ -587,16 +605,18 @@ impl Handler for CamelcaseHandler {
587605 let ast_view:: ImportNamedSpecifier {
588606 local, imported, ..
589607 } = import_named_specifier;
590- self . check_ident (
591- local,
592- IdentToCheck :: named_import (
593- local. inner ,
594- imported. as_ref ( ) . map ( |i| match i {
595- ast_view:: ModuleExportName :: Ident ( ident) => ident. sym ( ) ,
596- ast_view:: ModuleExportName :: Str ( str) => str. value ( ) ,
597- } ) ,
598- ) ,
599- ) ;
608+ if let Some ( imported) = & imported {
609+ self . check_ident (
610+ local,
611+ IdentToCheck :: named_import (
612+ local. inner ,
613+ Some ( match imported {
614+ ast_view:: ModuleExportName :: Ident ( ident) => ident. sym ( ) ,
615+ ast_view:: ModuleExportName :: Str ( str) => str. value ( ) ,
616+ } ) ,
617+ ) ,
618+ ) ;
619+ }
600620 }
601621
602622 fn import_default_specifier (
@@ -719,6 +739,28 @@ impl Handler for CamelcaseHandler {
719739 }
720740}
721741
742+ fn pat_in_var_declarator ( pat : Node ) -> bool {
743+ for ancestor in pat. ancestors ( ) {
744+ match ancestor. kind ( ) {
745+ NodeKind :: VarDeclarator => {
746+ return true ;
747+ }
748+ NodeKind :: ArrayPat
749+ | NodeKind :: ObjectPat
750+ | NodeKind :: AssignPat
751+ | NodeKind :: AssignPatProp
752+ | NodeKind :: RestPat
753+ | NodeKind :: KeyValuePatProp => {
754+ // keep going
755+ }
756+ _ => {
757+ return false ;
758+ }
759+ }
760+ }
761+ false
762+ }
763+
722764#[ cfg( test) ]
723765mod tests {
724766 use super :: * ;
@@ -788,6 +830,7 @@ mod tests {
788830 key_name : s ( "foo_bar" ) ,
789831 value_name : None ,
790832 has_default : false ,
833+ is_destructuring : true ,
791834 } ,
792835 "Consider replacing `{ foo_bar }` with `{ foo_bar: fooBar }`" ,
793836 ) ,
@@ -796,6 +839,7 @@ mod tests {
796839 key_name : s ( "foo_bar" ) ,
797840 value_name : Some ( s ( "snake_case" ) ) ,
798841 has_default : false ,
842+ is_destructuring : true ,
799843 } ,
800844 "Consider renaming `snake_case` to `snakeCase`" ,
801845 ) ,
@@ -804,14 +848,26 @@ mod tests {
804848 key_name : s ( "foo_bar" ) ,
805849 value_name : None ,
806850 has_default : true ,
851+ is_destructuring : true ,
807852 } ,
808853 "Consider replacing `{ foo_bar = .. }` with `{ foo_bar: fooBar = .. }`" ,
809854 ) ,
855+ (
856+ IdentToCheck :: ObjectPat {
857+ key_name : s ( "foo_bar" ) ,
858+ value_name : None ,
859+ has_default : true ,
860+ is_destructuring : false ,
861+ } ,
862+ // not destructuring, so suggest a rename
863+ "Consider renaming `foo_bar` to `fooBar`" ,
864+ ) ,
810865 (
811866 IdentToCheck :: ObjectPat {
812867 key_name : s ( "foo_bar" ) ,
813868 value_name : Some ( s ( "snake_case" ) ) ,
814869 has_default : true ,
870+ is_destructuring : true ,
815871 } ,
816872 "Consider renaming `snake_case` to `snakeCase`" ,
817873 ) ,
@@ -869,9 +925,14 @@ mod tests {
869925 r#"var { category_id: category } = query;"# ,
870926 r#"var { _leading } = query;"# ,
871927 r#"var { trailing_ } = query;"# ,
928+ r#"var { or_middle } = query;"# ,
929+ r#"var { category_id = 1 } = query;"# ,
930+ r#"var { category_id: { property_test } } = query;"# ,
931+ r#"const { no_camelcased = false } = bar;"# ,
872932 r#"import { camelCased } from "external module";"# ,
873933 r#"import { _leading } from "external module";"# ,
874934 r#"import { trailing_ } from "external module";"# ,
935+ r#"import { or_middle } from "external module";"# ,
875936 r#"import { no_camelcased as camelCased } from "external-module";"# ,
876937 r#"import { no_camelcased as _leading } from "external-module";"# ,
877938 r#"import { no_camelcased as trailing_ } from "external-module";"# ,
@@ -989,48 +1050,20 @@ mod tests {
9891050 hint: "Consider renaming `category_alias` to `categoryAlias`" ,
9901051 }
9911052 ] ,
992- r#"var { category_id } = query;"# : [
993- {
994- col: 6 ,
995- message: "Identifier 'category_id' is not in camel case." ,
996- hint: "Consider replacing `{ category_id }` with `{ category_id: categoryId }`" ,
997- }
998- ] ,
9991053 r#"var { category_id: category_id } = query;"# : [
10001054 {
10011055 col: 19 ,
10021056 message: "Identifier 'category_id' is not in camel case." ,
10031057 hint: "Consider renaming `category_id` to `categoryId`" ,
10041058 }
10051059 ] ,
1006- r#"var { category_id = 1 } = query;"# : [
1007- {
1008- col: 6 ,
1009- message: "Identifier 'category_id' is not in camel case." ,
1010- hint: "Consider replacing `{ category_id = .. }` with `{ category_id: categoryId = .. }`" ,
1011- }
1012- ] ,
1013- r#"import no_camelcased from "external-module";"# : [
1014- {
1015- col: 7 ,
1016- message: "Identifier 'no_camelcased' is not in camel case." ,
1017- hint: "Consider renaming `no_camelcased` to `noCamelcased`" ,
1018- }
1019- ] ,
10201060 r#"import * as no_camelcased from "external-module";"# : [
10211061 {
10221062 col: 12 ,
10231063 message: "Identifier 'no_camelcased' is not in camel case." ,
10241064 hint: "Consider renaming `no_camelcased` to `noCamelcased`" ,
10251065 }
10261066 ] ,
1027- r#"import { no_camelcased } from "external-module";"# : [
1028- {
1029- col: 9 ,
1030- message: "Identifier 'no_camelcased' is not in camel case." ,
1031- hint: "Consider replacing `{ no_camelcased }` with `{ no_camelcased as noCamelcased }`" ,
1032- }
1033- ] ,
10341067 r#"import { no_camelcased as no_camel_cased } from "external module";"# : [
10351068 {
10361069 col: 26 ,
@@ -1045,27 +1078,6 @@ mod tests {
10451078 hint: "Consider renaming `no_camel_cased` to `noCamelCased`" ,
10461079 }
10471080 ] ,
1048- r#"import { camelCased, no_camelcased } from "external-module";"# : [
1049- {
1050- col: 21 ,
1051- message: "Identifier 'no_camelcased' is not in camel case." ,
1052- hint: "Consider replacing `{ no_camelcased }` with `{ no_camelcased as noCamelcased }`" ,
1053- }
1054- ] ,
1055- r#"import { no_camelcased as camelCased, another_no_camelcased } from "external-module";"# : [
1056- {
1057- col: 38 ,
1058- message: "Identifier 'another_no_camelcased' is not in camel case." ,
1059- hint: "Consider replacing `{ another_no_camelcased }` with `{ another_no_camelcased as anotherNoCamelcased }`" ,
1060- }
1061- ] ,
1062- r#"import camelCased, { no_camelcased } from "external-module";"# : [
1063- {
1064- col: 21 ,
1065- message: "Identifier 'no_camelcased' is not in camel case." ,
1066- hint: "Consider replacing `{ no_camelcased }` with `{ no_camelcased as noCamelcased }`" ,
1067- }
1068- ] ,
10691081 r#"import no_camelcased, { another_no_camelcased as camelCased } from "external-module";"# : [
10701082 {
10711083 col: 7 ,
@@ -1098,14 +1110,14 @@ mod tests {
10981110 {
10991111 col: 15 ,
11001112 message: "Identifier 'no_camelcased' is not in camel case." ,
1101- hint: "Consider replacing `{ no_camelcased }` with `{ no_camelcased: noCamelcased } `" ,
1113+ hint: "Consider renaming ` no_camelcased` to ` noCamelcased`" ,
11021114 }
11031115 ] ,
11041116 r#"function foo({ no_camelcased = 'default value' }) {};"# : [
11051117 {
11061118 col: 15 ,
11071119 message: "Identifier 'no_camelcased' is not in camel case." ,
1108- hint: "Consider replacing `{ no_camelcased = .. }` with `{ no_camelcased: noCamelcased = .. } `" ,
1120+ hint: "Consider renaming ` no_camelcased` to ` noCamelcased`" ,
11091121 }
11101122 ] ,
11111123 r#"const no_camelcased = 0; function foo({ camelcased_value = no_camelcased }) {}"# : [
@@ -1117,7 +1129,7 @@ mod tests {
11171129 {
11181130 col: 40 ,
11191131 message: "Identifier 'camelcased_value' is not in camel case." ,
1120- hint: "Consider replacing `{ camelcased_value = .. }` with `{ camelcased_value: camelcasedValue = .. } `" ,
1132+ hint: "Consider renaming ` camelcased_value` to ` camelcasedValue`" ,
11211133 }
11221134 ] ,
11231135 r#"const { bar: no_camelcased } = foo;"# : [
@@ -1141,25 +1153,18 @@ mod tests {
11411153 hint: "Consider renaming `no_camelcased` to `noCamelcased`" ,
11421154 }
11431155 ] ,
1144- r#"var { foo: bar_baz = 1 } = quz;"# : [
1145- {
1146- col: 11 ,
1147- message: "Identifier 'bar_baz' is not in camel case." ,
1148- hint: "Consider renaming `bar_baz` to `barBaz`" ,
1149- }
1150- ] ,
1151- r#"const { no_camelcased = false } = bar;"# : [
1156+ r#"function foo({ isCamelcased: { no_camelcased } }) {};"# : [
11521157 {
1153- col: 8 ,
1158+ col: 31 ,
11541159 message: "Identifier 'no_camelcased' is not in camel case." ,
1155- hint: "Consider replacing `{ no_camelcased = .. }` with `{ no_camelcased: noCamelcased = .. } `" ,
1160+ hint: "Consider renaming ` no_camelcased` to ` noCamelcased`" ,
11561161 }
11571162 ] ,
1158- r#"const { no_camelcased = foo_bar } = bar ;"# : [
1163+ r#"var { foo: bar_baz = 1 } = quz ;"# : [
11591164 {
1160- col: 8 ,
1161- message: "Identifier 'no_camelcased ' is not in camel case." ,
1162- hint: "Consider replacing `{ no_camelcased = .. }` with `{ no_camelcased: noCamelcased = .. } `" ,
1165+ col: 11 ,
1166+ message: "Identifier 'bar_baz ' is not in camel case." ,
1167+ hint: "Consider renaming `bar_baz` to `barBaz `" ,
11631168 }
11641169 ] ,
11651170 r#"const f = function no_camelcased() {};"# : [
0 commit comments