33import ast
44import re
55from collections .abc import Sequence
6- from glob import glob
6+ from dataclasses import dataclass
77from keyword import kwlist
88from pathlib import Path
99from textwrap import indent
1212from typing import Iterator
1313
1414import click
15+ from typing_extensions import TypeGuard
1516
1617from idom import html
1718
@@ -64,73 +65,32 @@ def generate_rewrite(file: Path, source: str) -> None:
6465 for parents , node in walk_with_parent (tree ):
6566 if isinstance (node , ast .Call ):
6667 func = node .func
67- match func :
68- case ast .Attribute ():
69- name = func .attr
70- case ast .Name (ctx = ast .Load ()):
71- name = func .id
72- case _:
73- name = ""
68+ if isinstance (func , ast .Attribute ):
69+ name = func .attr
70+ elif isinstance (func , ast .Name ):
71+ name = func .id
72+ else :
73+ name = ""
7474 if hasattr (html , name ) or name == "vdom" :
7575 if name == "vdom" :
76- # first arg is the tag name
77- node_args_pre = node . args [: 1 ]
78- node .args = node .args [1 :]
76+ maybe_attr_dict_node = node . args [ 1 ]
77+ # remove attr dict from new args
78+ new_args = node .args [: 1 ] + node .args [2 :]
7979 else :
80- node_args_pre = []
81-
82- match node .args :
83- case [ast .Dict (keys , values ), * _]:
84- new_kwargs = list (node .keywords )
85- should_change = True
86- for k , v in zip (keys , values ):
87- if isinstance (k , ast .Constant ) and isinstance (k .value , str ):
88- if k .value == "tagName" :
89- # this is a vdom dict declaration
90- should_change = False
91- break
92- new_kwargs .append (
93- ast .keyword (arg = conv_attr_name (k .value ), value = v )
94- )
95- else :
96- new_kwargs = [ast .keyword (arg = None , value = node .args [0 ])]
97- should_change = True
98- break
99- if should_change :
100- node .args = node_args_pre + node .args [1 :]
101- node .keywords = new_kwargs
102- changed .append ((node , * parents ))
103- case [
104- ast .Call (
105- func = ast .Name (id = "dict" , ctx = ast .Load ()),
106- args = args ,
107- keywords = kwargs ,
108- ),
109- * _,
110- ]:
111- new_kwargs = [
112- * [ast .keyword (arg = None , value = a ) for a in args ],
113- * node .keywords ,
114- ]
115- for kw in kwargs :
116- if kw .arg == "tagName" :
117- # this is a vdom dict declaration
118- break
119- if kw .arg is not None :
120- new_kwargs .append (
121- ast .keyword (
122- arg = conv_attr_name (kw .arg ), value = kw .value
123- )
124- )
125- else :
126- new_kwargs .append (kw )
80+ maybe_attr_dict_node = node .args [0 ]
81+ # remove attr dict from new args
82+ new_args = node .args [1 :]
83+
84+ if node .args :
85+ new_keyword_info = extract_keywords (maybe_attr_dict_node )
86+ if new_keyword_info is not None :
87+ if new_keyword_info .replace :
88+ node .keywords = new_keyword_info .keywords
12789 else :
128- node .args = node_args_pre + node .args [1 :]
129- node .keywords = new_kwargs
130- changed .append ((node , * parents ))
90+ node .keywords .extend (new_keyword_info .keywords )
13191
132- case _:
133- pass
92+ node . args = new_args
93+ changed . append (( node , * parents ))
13494
13595 if not changed :
13696 return
@@ -202,6 +162,39 @@ def generate_rewrite(file: Path, source: str) -> None:
202162 return "\n " .join (lines )
203163
204164
165+ def extract_keywords (node : ast .AST ) -> KeywordInfo | None :
166+ if isinstance (node , ast .Dict ):
167+ keywords : list [ast .keyword ] = []
168+ for k , v in zip (node .keys , node .values ):
169+ if isinstance (k , ast .Constant ) and isinstance (k .value , str ):
170+ if k .value == "tagName" :
171+ # this is a vdom dict declaration
172+ return None
173+ keywords .append (ast .keyword (arg = conv_attr_name (k .value ), value = v ))
174+ else :
175+ return KeywordInfo (
176+ replace = True ,
177+ keywords = [ast .keyword (arg = None , value = node )],
178+ )
179+ return KeywordInfo (replace = False , keywords = keywords )
180+ elif (
181+ isinstance (node , ast .Call )
182+ and isinstance (node .func , ast .Name )
183+ and node .func .id == "dict"
184+ and isinstance (node .func .ctx , ast .Load )
185+ ):
186+ keywords = [ast .keyword (arg = None , value = a ) for a in node .args ]
187+ for kw in node .keywords :
188+ if kw .arg == "tagName" :
189+ # this is a vdom dict declaration
190+ return None
191+ if kw .arg is not None :
192+ keywords .append (ast .keyword (arg = conv_attr_name (kw .arg ), value = kw .value ))
193+ else :
194+ keywords .append (kw )
195+ return KeywordInfo (replace = False , keywords = keywords )
196+
197+
205198def find_comments (lines : list [str ]) -> list [str ]:
206199 iter_lines = iter (lines )
207200 return [
@@ -223,3 +216,9 @@ def walk_with_parent(
223216def conv_attr_name (name : str ) -> str :
224217 new_name = CAMEL_CASE_SUB_PATTERN .sub ("_" , name ).replace ("-" , "_" ).lower ()
225218 return f"{ new_name } _" if new_name in kwlist else new_name
219+
220+
221+ @dataclass
222+ class KeywordInfo :
223+ replace : bool
224+ keywords : Sequence [ast .keyword ]
0 commit comments