Skip to content

Commit 5277676

Browse files
committed
rewrite style prop + other fixes
1 parent 3aa249d commit 5277676

File tree

3 files changed

+74
-38
lines changed

3 files changed

+74
-38
lines changed

src/idom/_console/ast_utils.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,9 @@ def find_element_constructor_usages(
101101
continue
102102

103103
func = node.func
104-
if (
105-
isinstance(func, ast.Attribute)
106-
and isinstance(func.value, ast.Name)
107-
and func.value.id == "html"
104+
if isinstance(func, ast.Attribute) and (
105+
(isinstance(func.value, ast.Name) and func.value.id == "html")
106+
or (isinstance(func.value, ast.Attribute) and func.value.attr == "html")
108107
):
109108
name = func.attr
110109
elif isinstance(func, ast.Name):

src/idom/_console/rewrite_camel_case_props.py

+59-34
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import ast
44
import re
55
import sys
6+
from copy import copy
67
from keyword import kwlist
78
from pathlib import Path
9+
from typing import Callable
810

911
import click
1012

@@ -46,43 +48,66 @@ def generate_rewrite(file: Path, source: str) -> str | None:
4648
def find_nodes_to_change(tree: ast.AST) -> list[ChangedNode]:
4749
changed: list[ChangedNode] = []
4850
for el_info in find_element_constructor_usages(tree):
49-
if isinstance(el_info.props, ast.Dict):
50-
did_change = False
51-
keys: list[ast.expr | None] = []
52-
for k in el_info.props.keys:
53-
if isinstance(k, ast.Constant) and isinstance(k.value, str):
54-
new_prop_name = conv_attr_name(k.value)
55-
if new_prop_name != k.value:
56-
did_change = True
57-
keys.append(ast.Constant(new_prop_name))
58-
else:
59-
keys.append(k)
60-
else:
61-
keys.append(k)
62-
if not did_change:
63-
continue
64-
el_info.props.keys = keys
65-
else:
66-
did_change = False
67-
keywords: list[ast.keyword] = []
68-
for kw in el_info.props.keywords:
69-
if kw.arg is not None:
70-
new_prop_name = conv_attr_name(kw.arg)
71-
if new_prop_name != kw.arg:
72-
did_change = True
73-
keywords.append(ast.keyword(arg=new_prop_name, value=kw.value))
74-
else:
75-
keywords.append(kw)
76-
else:
77-
keywords.append(kw)
78-
if not did_change:
79-
continue
80-
el_info.props.keywords = keywords
81-
82-
changed.append(ChangedNode(el_info.call, el_info.parents))
51+
if _rewrite_props(el_info.props, _construct_prop_item):
52+
changed.append(ChangedNode(el_info.call, el_info.parents))
8353
return changed
8454

8555

8656
def conv_attr_name(name: str) -> str:
8757
new_name = CAMEL_CASE_SUB_PATTERN.sub("_", name).lower()
8858
return f"{new_name}_" if new_name in kwlist else new_name
59+
60+
61+
def _construct_prop_item(key: str, value: ast.expr) -> tuple[str, ast.expr]:
62+
if key == "style" and isinstance(value, (ast.Dict, ast.Call)):
63+
new_value = copy(value)
64+
if _rewrite_props(
65+
new_value,
66+
lambda k, v: (
67+
(k, v)
68+
# avoid infinite recursion
69+
if k == "style"
70+
else _construct_prop_item(k, v)
71+
),
72+
):
73+
value = new_value
74+
else:
75+
key = conv_attr_name(key)
76+
return key, value
77+
78+
79+
def _rewrite_props(
80+
props_node: ast.Dict | ast.Call,
81+
constructor: Callable[[str, ast.expr], tuple[str, ast.expr]],
82+
) -> bool:
83+
if isinstance(props_node, ast.Dict):
84+
did_change = False
85+
keys: list[ast.expr | None] = []
86+
values: list[ast.expr] = []
87+
for k, v in zip(props_node.keys, props_node.values):
88+
if isinstance(k, ast.Constant) and isinstance(k.value, str):
89+
k_value, new_v = constructor(k.value, v)
90+
if k_value != k.value or new_v is not v:
91+
did_change = True
92+
k = ast.Constant(value=k_value)
93+
v = new_v
94+
keys.append(k)
95+
values.append(v)
96+
if not did_change:
97+
return False
98+
props_node.keys = keys
99+
props_node.values = values
100+
else:
101+
did_change = False
102+
keywords: list[ast.keyword] = []
103+
for kw in props_node.keywords:
104+
if kw.arg is not None:
105+
kw_arg, kw_value = constructor(kw.arg, kw.value)
106+
if kw_arg != kw.arg or kw_value is not kw.value:
107+
did_change = True
108+
kw = ast.keyword(arg=kw_arg, value=kw_value)
109+
keywords.append(kw)
110+
if not did_change:
111+
return
112+
props_node.keywords = keywords
113+
return True

tests/test__console/test_rewrite_camel_case_props.py

+12
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ def test_rewrite_camel_case_props_declarations_no_files():
4949
"html.div(dict(camelCase='test'))",
5050
"html.div(dict(camel_case='test'))",
5151
),
52+
(
53+
"idom.html.button({'onClick': block_forever})",
54+
"idom.html.button({'on_click': block_forever})",
55+
),
56+
(
57+
"html.div(dict(style={'testThing': test}))",
58+
"html.div(dict(style={'test_thing': test}))",
59+
),
60+
(
61+
"html.div(dict(style=dict(testThing=test)))",
62+
"html.div(dict(style=dict(test_thing=test)))",
63+
),
5264
(
5365
"vdom('tag', dict(camelCase='test'))",
5466
"vdom('tag', dict(camel_case='test'))",

0 commit comments

Comments
 (0)