11from  __future__ import  annotations 
22
33import  ast 
4- import  re 
54from  copy  import  copy 
65from  keyword  import  kwlist 
76from  pathlib  import  Path 
1514    rewrite_changed_nodes ,
1615)
1716
18- CAMEL_CASE_SUB_PATTERN  =  re .compile (r"(?<!^)(?=[A-Z])" )
19- 
2017
2118@click .command () 
2219@click .argument ("paths" , nargs = - 1 , type = click .Path (exists = True )) 
23- def  rewrite_camel_case_props (paths : list [str ]) ->  None :
24-     """Rewrite camelCase props to snake_case""" 
25- 
20+ def  rewrite_props (paths : list [str ]) ->  None :
21+     """Rewrite snake_case props to camelCase within <PATHS>.""" 
2622    for  p  in  map (Path , paths ):
23+         # Process each file or recursively process each Python file in directories 
2724        for  f  in  [p ] if  p .is_file () else  p .rglob ("*.py" ):
2825            result  =  generate_rewrite (file = f , source = f .read_text (encoding = "utf-8" ))
2926            if  result  is  not   None :
3027                f .write_text (result )
3128
3229
3330def  generate_rewrite (file : Path , source : str ) ->  str  |  None :
34-     tree  =  ast .parse (source )
31+     """Generate the rewritten source code if changes are detected""" 
32+     tree  =  ast .parse (source )  # Parse the source code into an AST 
3533
36-     changed  =  find_nodes_to_change (tree )
34+     changed  =  find_nodes_to_change (tree )   # Find nodes that need to be changed 
3735    if  not  changed :
38-         return  None 
36+         return  None    # Return None if no changes are needed 
3937
40-     new  =  rewrite_changed_nodes (file , source , tree , changed )
38+     new  =  rewrite_changed_nodes (
39+         file , source , tree , changed 
40+     )  # Rewrite the changed nodes 
4141    return  new 
4242
4343
4444def  find_nodes_to_change (tree : ast .AST ) ->  list [ChangedNode ]:
45+     """Find nodes in the AST that need to be changed""" 
4546    changed : list [ChangedNode ] =  []
4647    for  el_info  in  find_element_constructor_usages (tree ):
48+         # Check if the props need to be rewritten 
4749        if  _rewrite_props (el_info .props , _construct_prop_item ):
50+             # Add the changed node to the list 
4851            changed .append (ChangedNode (el_info .call , el_info .parents ))
4952    return  changed 
5053
5154
5255def  conv_attr_name (name : str ) ->  str :
53-     new_name  =  CAMEL_CASE_SUB_PATTERN .sub ("_" , name ).lower ()
54-     return  f"{ new_name }  _"  if  new_name  in  kwlist  else  new_name 
56+     """Convert snake_case attribute name to camelCase""" 
57+     # Return early if the value is a Python keyword 
58+     if  name  in  kwlist :
59+         return  name 
60+ 
61+     # Return early if the value is not snake_case 
62+     if  "_"  not  in   name :
63+         return  name 
64+ 
65+     # Split the string by underscores 
66+     components  =  name .split ("_" )
67+ 
68+     # Capitalize the first letter of each component except the first one 
69+     # and join them together 
70+     return  components [0 ] +  "" .join (x .title () for  x  in  components [1 :])
5571
5672
5773def  _construct_prop_item (key : str , value : ast .expr ) ->  tuple [str , ast .expr ]:
74+     """Construct a new prop item with the converted key and possibly modified value""" 
5875    if  key  ==  "style"  and  isinstance (value , (ast .Dict , ast .Call )):
76+         # Create a copy of the value to avoid modifying the original 
5977        new_value  =  copy (value )
6078        if  _rewrite_props (
6179            new_value ,
6280            lambda  k , v : (
6381                (k , v )
64-                 # avoid  infinite recursion 
82+                 # Avoid  infinite recursion 
6583                if  k  ==  "style" 
6684                else  _construct_prop_item (k , v )
6785            ),
6886        ):
87+             # Update the value if changes were made 
6988            value  =  new_value 
7089    else :
90+         # Convert the key to camelCase 
7191        key  =  conv_attr_name (key )
7292    return  key , value 
7393
@@ -76,12 +96,15 @@ def _rewrite_props(
7696    props_node : ast .Dict  |  ast .Call ,
7797    constructor : Callable [[str , ast .expr ], tuple [str , ast .expr ]],
7898) ->  bool :
99+     """Rewrite the props in the given AST node using the provided constructor""" 
100+     did_change  =  False 
79101    if  isinstance (props_node , ast .Dict ):
80-         did_change  =  False 
81102        keys : list [ast .expr  |  None ] =  []
82103        values : list [ast .expr ] =  []
104+         # Iterate over the keys and values in the dictionary 
83105        for  k , v  in  zip (props_node .keys , props_node .values ):
84106            if  isinstance (k , ast .Constant ) and  isinstance (k .value , str ):
107+                 # Construct the new key and value 
85108                k_value , new_v  =  constructor (k .value , v )
86109                if  k_value  !=  k .value  or  new_v  is  not   v :
87110                    did_change  =  True 
@@ -90,20 +113,22 @@ def _rewrite_props(
90113            keys .append (k )
91114            values .append (v )
92115        if  not  did_change :
93-             return  False 
116+             return  False    # Return False if no changes were made 
94117        props_node .keys  =  keys 
95118        props_node .values  =  values 
96119    else :
97120        did_change  =  False 
98121        keywords : list [ast .keyword ] =  []
122+         # Iterate over the keywords in the call 
99123        for  kw  in  props_node .keywords :
100124            if  kw .arg  is  not   None :
125+                 # Construct the new keyword argument and value 
101126                kw_arg , kw_value  =  constructor (kw .arg , kw .value )
102127                if  kw_arg  !=  kw .arg  or  kw_value  is  not   kw .value :
103128                    did_change  =  True 
104129                kw  =  ast .keyword (arg = kw_arg , value = kw_value )
105130            keywords .append (kw )
106131        if  not  did_change :
107-             return  False 
132+             return  False    # Return False if no changes were made 
108133        props_node .keywords  =  keywords 
109134    return  True 
0 commit comments