3
3
import ast
4
4
import re
5
5
from collections .abc import Sequence
6
- from glob import glob
6
+ from dataclasses import dataclass
7
7
from keyword import kwlist
8
8
from pathlib import Path
9
9
from textwrap import indent
12
12
from typing import Iterator
13
13
14
14
import click
15
+ from typing_extensions import TypeGuard
15
16
16
17
from idom import html
17
18
@@ -64,73 +65,32 @@ def generate_rewrite(file: Path, source: str) -> None:
64
65
for parents , node in walk_with_parent (tree ):
65
66
if isinstance (node , ast .Call ):
66
67
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 = ""
74
74
if hasattr (html , name ) or name == "vdom" :
75
75
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 :]
79
79
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
127
89
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 )
131
91
132
- case _:
133
- pass
92
+ node . args = new_args
93
+ changed . append (( node , * parents ))
134
94
135
95
if not changed :
136
96
return
@@ -202,6 +162,39 @@ def generate_rewrite(file: Path, source: str) -> None:
202
162
return "\n " .join (lines )
203
163
204
164
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
+
205
198
def find_comments (lines : list [str ]) -> list [str ]:
206
199
iter_lines = iter (lines )
207
200
return [
@@ -223,3 +216,9 @@ def walk_with_parent(
223
216
def conv_attr_name (name : str ) -> str :
224
217
new_name = CAMEL_CASE_SUB_PATTERN .sub ("_" , name ).replace ("-" , "_" ).lower ()
225
218
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