Selaa lähdekoodia

Add state name into compiler

Nikhil Rao 2 vuotta sitten
vanhempi
säilyke
705557b484

+ 15 - 17
pynecone/compiler/templates.py

@@ -56,9 +56,7 @@ def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None)
 DOCUMENT_ROOT = join(
     [
         "{imports}",
-        "",
         "export default function Document() {{",
-        "",
         "return (",
         "{document}",
         ")",
@@ -74,17 +72,11 @@ COMPONENT = join(
     [
         "{imports}",
         "{custom_code}",
-        "",
         "{constants}",
-        "",
         "export default function Component() {{",
-        "",
         "{state}",
-        "",
         "{events}",
-        "",
         "{effects}",
-        "",
         "return (",
         "{render}",
         ")",
@@ -155,22 +147,28 @@ def format_event_declaration(fn: Callable) -> str:
 
 
 # Effects.
+ROUTER = constants.ROUTER
+RESULT = constants.RESULT
+PROCESSING = constants.PROCESSING
+STATE = constants.STATE
+EVENTS = constants.EVENTS
+SET_RESULT = format_state_setter(RESULT)
 USE_EFFECT = join(
     [
         "useEffect(() => {{",
         "  const update = async () => {{",
-        "    if (result.state != null) {{",
-        "      setState({{",
-        "        ...result.state,",
-        "        events: [...state.events, ...result.events],",
+        f"    if ({RESULT}.{STATE} != null) {{{{",
+        f"      {{set_state}}({{{{",
+        f"        ...{RESULT}.{STATE},",
+        f"        events: [...{{state}}.{EVENTS}, ...{RESULT}.{EVENTS}],",
         "      }})",
-        "      setResult({{",
-        "        ...result,",
-        "        state: null,",
-        "       processing: false,",
+        f"      {SET_RESULT}({{{{",
+        f"        ...{RESULT},",
+        f"        {{state}}: null,",
+        f"       {PROCESSING}: false,",
         "      }})",
         "    }}",
-        f"    await updateState({{state}}, {{result}}, {{set_result}}, {EVENT_ENDPOINT}, {constants.ROUTER})",
+        f"    await updateState({{state}}, {RESULT}, {SET_RESULT}, {EVENT_ENDPOINT}, {ROUTER})",
         "  }}",
         "  update()",
         "}})",

+ 5 - 8
pynecone/compiler/utils.py

@@ -115,9 +115,9 @@ def compile_state(state: Type[State]) -> str:
         state=state.get_name(), initial_state=json.dumps(initial_state)
     )
     initial_result = {
-        "state": None,
-        "events": [],
-        "processing": False,
+        constants.STATE: None,
+        constants.EVENTS: [],
+        constants.PROCESSING: False,
     }
     result = templates.format_state(
         state="result",
@@ -151,11 +151,8 @@ def compile_effects(state: Type[State]) -> str:
         A string of the compiled effects for the component.
     """
     state_name = state.get_name()
-    result_name = "result"
-    set_result = templates.format_state_setter(result_name)
-    return templates.USE_EFFECT(
-        state=state_name, result=result_name, set_result=set_result
-    )
+    set_state = templates.format_state_setter(state_name)
+    return templates.USE_EFFECT(state=state_name, set_state=set_state)
 
 
 def compile_render(component: Component) -> str:

+ 65 - 63
pynecone/components/tags/tag.py

@@ -5,7 +5,7 @@ from __future__ import annotations
 import json
 import os
 import re
-from typing import Any, Dict, Optional, Union
+from typing import TYPE_CHECKING, Any, Dict, Optional, Union
 
 from plotly.graph_objects import Figure
 from plotly.io import to_json
@@ -15,6 +15,9 @@ from pynecone.base import Base
 from pynecone.event import EventChain
 from pynecone.var import Var
 
+if TYPE_CHECKING:
+    from pynecone.components.component import ComponentStyle
+
 
 class Tag(Base):
     """A React tag."""
@@ -43,87 +46,86 @@ class Tag(Base):
         super().__init__(*args, **kwargs)
 
     @staticmethod
-    def format_attr_value(
-        value: Union[Var, EventChain, Dict[str, Var], str],
+    def format_prop(
+        prop: Union[Var, EventChain, ComponentStyle, str],
     ) -> Union[int, float, str]:
-        """Format an attribute value.
+        """Format a prop.
 
         Args:
-            value: The value of the attribute
+            prop: The prop to format.
 
         Returns:
-            The formatted value to display within the tag.
+            The formatted prop to display within a tag.
         """
 
         def format_fn(value):
             args = ",".join([":".join((name, val)) for name, val in value.args])
             return f"E(\"{utils.to_snake_case(value.handler.fn.__qualname__)}\", {utils.wrap(args, '{')})"
 
-        # Handle var attributes.
-        if isinstance(value, Var):
-            if not value.is_local or value.is_string:
-                return str(value)
-            if issubclass(value.type_, str):
-                value = json.dumps(value.full_name)
-                value = re.sub('"{', "", value)
-                value = re.sub('}"', "", value)
-                value = re.sub('"`', '{"', value)
-                value = re.sub('`"', '"}', value)
-                return value
-            value = value.full_name
+        # Handle var props.
+        if isinstance(prop, Var):
+            if not prop.is_local or prop.is_string:
+                return str(prop)
+            if issubclass(prop.type_, str):
+                prop = json.dumps(prop.full_name)
+                prop = re.sub('"{', "", prop)
+                prop = re.sub('}"', "", prop)
+                prop = re.sub('"`', '{"', prop)
+                prop = re.sub('`"', '"}', prop)
+                return prop
+            prop = prop.full_name
 
         # Handle events.
-        elif isinstance(value, EventChain):
-            local_args = ",".join(value.events[0].local_args)
-            fns = ",".join([format_fn(event) for event in value.events])
-            value = f"({local_args}) => Event([{fns}])"
+        elif isinstance(prop, EventChain):
+            local_args = ",".join(prop.events[0].local_args)
+            fns = ",".join([format_fn(event) for event in prop.events])
+            prop = f"({local_args}) => Event([{fns}])"
 
         # Handle other types.
-        elif isinstance(value, str):
-            if utils.is_wrapped(value, "{"):
-                return value
-            return json.dumps(value)
+        elif isinstance(prop, str):
+            if utils.is_wrapped(prop, "{"):
+                return prop
+            return json.dumps(prop)
 
-        elif isinstance(value, Figure):
-            value = json.loads(to_json(value))["data"]
+        elif isinstance(prop, Figure):
+            prop = json.loads(to_json(prop))["data"]
 
         # For dictionaries, convert any properties to strings.
         else:
-            if isinstance(value, dict):
-                value = json.dumps(
+            if isinstance(prop, dict):
+                prop = json.dumps(
                     {
                         key: str(val) if isinstance(val, Var) else val
-                        for key, val in value.items()
+                        for key, val in prop.items()
                     }
                 )
             else:
-                value = json.dumps(value)
+                prop = json.dumps(prop)
 
-            value = re.sub('"{', "", value)
-            value = re.sub('}"', "", value)
-            value = re.sub('"`', '{"', value)
-            value = re.sub('`"', '"}', value)
+            prop = re.sub('"{', "", prop)
+            prop = re.sub('}"', "", prop)
+            prop = re.sub('"`', '{"', prop)
+            prop = re.sub('`"', '"}', prop)
 
         # Wrap the variable in braces.
-        assert isinstance(value, str), "The value must be a string."
-        return utils.wrap(value, "{", check_first=False)
+        assert isinstance(prop, str), "The prop must be a string."
+        return utils.wrap(prop, "{", check_first=False)
 
     def format_props(self) -> str:
-        """Format a dictionary of attributes.
+        """Format the tag's props.
 
         Returns:
-            The formatted attributes.
+            The formatted props.
         """
-        # If there are no attributes, return an empty string.
+        # If there are no props, return an empty string.
         if len(self.props) == 0:
             return ""
 
-        # Get the string representation of all the attributes joined.
-        # We need a space at the beginning for formatting.
+        # Format all the props.
         return os.linesep.join(
-            f"{name}={self.format_attr_value(value)}"
-            for name, value in self.props.items()
-            if value is not None
+            f"{name}={self.format_prop(prop)}"
+            for name, prop in self.props.items()
+            if prop is not None
         )
 
     def __str__(self) -> str:
@@ -132,7 +134,7 @@ class Tag(Base):
         Returns:
             The React code to render the tag.
         """
-        # Get the tag attributes.
+        # Get the tag props.
         props_str = self.format_props()
         if len(props_str) > 0:
             props_str = " " + props_str
@@ -149,33 +151,33 @@ class Tag(Base):
         return tag_str
 
     def add_props(self, **kwargs: Optional[Any]) -> Tag:
-        """Add attributes to the tag.
+        """Add props to the tag.
 
         Args:
-            **kwargs: The attributes to add.
+            **kwargs: The props to add.
 
         Returns:
-            The tag with the attributes added.
+            The tag with the props added.
         """
         self.props.update(
             {
-                utils.to_camel_case(name): attr
-                if utils._isinstance(attr, Union[EventChain, dict])
-                else Var.create(attr)
-                for name, attr in kwargs.items()
-                if self.is_valid_attr(attr)
+                utils.to_camel_case(name): prop
+                if utils._isinstance(prop, Union[EventChain, dict])
+                else Var.create(prop)
+                for name, prop in kwargs.items()
+                if self.is_valid_prop(prop)
             }
         )
         return self
 
     def remove_props(self, *args: str) -> Tag:
-        """Remove attributes from the tag.
+        """Remove props from the tag.
 
         Args:
-            *args: The attributes to remove.
+            *args: The props to remove.
 
         Returns:
-            The tag with the attributes removed.
+            The tag with the props removed.
         """
         for name in args:
             if name in self.props:
@@ -183,13 +185,13 @@ class Tag(Base):
         return self
 
     @staticmethod
-    def is_valid_attr(attr: Optional[Var]) -> bool:
-        """Check if the attr is valid.
+    def is_valid_prop(prop: Optional[Var]) -> bool:
+        """Check if the prop is valid.
 
         Args:
-            attr: The value to check.
+            prop: The prop to check.
 
         Returns:
-            Whether the value is valid.
+            Whether the prop is valid.
         """
-        return attr is not None and not (isinstance(attr, dict) and len(attr) == 0)
+        return prop is not None and not (isinstance(prop, dict) and len(prop) == 0)

+ 8 - 0
pynecone/constants.py

@@ -70,6 +70,14 @@ APP_VAR = "app"
 API_VAR = "api"
 # The name of the router variable.
 ROUTER = "router"
+# The name of the variable to hold API results.
+RESULT = "result"
+# The name of the process variable.
+PROCESSING = "processing"
+# The name of the state variable.
+STATE = "state"
+# The name of the events variable.
+EVENTS = "events"
 # The name of the initial hydrate event.
 HYDRATE = "hydrate"
 # The name of the index page.