11from html .parser import HTMLParser as _HTMLParser
22
3- from typing import List , Tuple , Any , Dict , Union , Optional , TypeVar , Generic , Callable
3+ from typing import List , Tuple , Any , Dict , TypeVar , Generic , Callable
44
55
66_R = TypeVar ("_R" , bound = Any ) # Var reference
@@ -41,18 +41,18 @@ def handle():
4141 return idom.node("button", "Use" eventHandlers=events)
4242 """
4343
44- __slots__ = ("__current " ,)
44+ __slots__ = ("_current " ,)
4545
4646 def __init__ (self , value : _R ) -> None :
47- self .__current = value
47+ self ._current = value
4848
4949 def set (self , new : _R ) -> _R :
50- old = self .__current
51- self .__current = new
50+ old = self ._current
51+ self ._current = new
5252 return old
5353
5454 def get (self ) -> _R :
55- return self .__current
55+ return self ._current
5656
5757 def __eq__ (self , other : Any ) -> bool :
5858 if isinstance (other , Var ):
@@ -64,38 +64,46 @@ def __repr__(self) -> str:
6464 return "Var(%r)" % self .get ()
6565
6666
67- _ModelOrStr = Union [Dict [str , Any ], str ]
68- _ModelTransform = Callable [[_ModelOrStr ], None ]
67+ _ModelTransform = Callable [[Dict [str , Any ]], Any ]
6968
7069
71- def html_to_vdom (
72- source : str , transform : Optional [_ModelTransform ] = None
73- ) -> List [Dict [str , Any ]]:
70+ def html_to_vdom (source : str , * transforms : _ModelTransform ) -> Dict [str , Any ]:
7471 """Transform HTML into a DOM model
7572
7673 Parameters:
7774 source:
7875 The raw HTML as a string
79- transform :
80- A function for transforming each model as it is created. For example,
81- you might use a transform function to add highlighting to a ``<code/>``
82- block.
76+ transforms :
77+ Functions of the form ``transform(old) -> new`` where ``old`` is a VDOM
78+ dictionary which will be replaced by ``new``. You might use a transform
79+ function to add highlighting to a ``<code/>`` block.
8380 """
84- parser = HtmlParser (transform )
81+ parser = HtmlParser ()
8582 parser .feed (source )
86- return parser .model ()
83+ root = parser .model ()
84+ to_visit = [root ]
85+ while to_visit :
86+ node = to_visit .pop (0 )
87+ if isinstance (node , dict ) and "children" in node :
88+ transformed = []
89+ for child in node ["children" ]:
90+ if isinstance (child , dict ):
91+ for t in transforms :
92+ child = t (child )
93+ if child is not None :
94+ transformed .append (child )
95+ to_visit .append (child )
96+ node ["children" ] = transformed
97+ if "attributes" in node and not node ["attributes" ]:
98+ del node ["attributes" ]
99+ if "children" in node and not node ["children" ]:
100+ del node ["children" ]
101+ return root
87102
88103
89104class HtmlParser (_HTMLParser ):
90- def __init__ (self , transform : Optional [_ModelTransform ] = None ):
91- super ().__init__ ()
92- if transform is not None :
93- self ._transform = transform
94-
95- def model (self ) -> List [Dict [str , Any ]]:
96- root : Dict [str , Any ] = self ._node_stack [0 ]
97- root_children : List [Dict [str , Any ]] = root ["children" ]
98- return root_children
105+ def model (self ) -> Dict [str , Any ]:
106+ return self ._node_stack [0 ]
99107
100108 def feed (self , data : str ) -> None :
101109 self ._node_stack .append (self ._make_node ("div" , {}))
@@ -112,12 +120,7 @@ def handle_starttag(self, tag: str, attrs: List[Tuple[str, str]]) -> None:
112120 self ._node_stack .append (new )
113121
114122 def handle_endtag (self , tag : str ) -> None :
115- node = self ._node_stack .pop (- 1 )
116- self ._transform (node )
117- if not node ["attributes" ]:
118- del node ["attributes" ]
119- if not node ["children" ]:
120- del node ["children" ]
123+ del self ._node_stack [- 1 ]
121124
122125 def handle_data (self , data : str ) -> None :
123126 self ._node_stack [- 1 ]["children" ].append (data )
@@ -134,7 +137,3 @@ def _make_node(tag: str, attrs: Dict[str, Any]) -> Dict[str, Any]:
134137 style_dict [camel_case_key ] = v
135138 attrs ["style" ] = style_dict
136139 return {"tagName" : tag , "attributes" : attrs , "children" : []}
137-
138- @staticmethod
139- def _transform (node : Dict [str , Any ]) -> None :
140- ...
0 commit comments