compiler.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. """Compiler variables."""
  2. import dataclasses
  3. import enum
  4. from enum import Enum
  5. from types import SimpleNamespace
  6. from reflex.constants import Dirs
  7. from reflex.utils.imports import ImportVar
  8. # The prefix used to create setters for state vars.
  9. SETTER_PREFIX = "set_"
  10. # The file used to specify no compilation.
  11. NOCOMPILE_FILE = "nocompile"
  12. class Ext(SimpleNamespace):
  13. """Extension used in Reflex."""
  14. # The extension for JS files.
  15. JS = ".js"
  16. # The extension for python files.
  17. PY = ".py"
  18. # The extension for css files.
  19. CSS = ".css"
  20. # The extension for zip files.
  21. ZIP = ".zip"
  22. # The extension for executable files on Windows.
  23. EXE = ".exe"
  24. # The extension for markdown files.
  25. MD = ".md"
  26. class CompileVars(SimpleNamespace):
  27. """The variables used during compilation."""
  28. # The expected variable name where the rx.App is stored.
  29. APP = "app"
  30. # The expected variable name where the API object is stored for deployment.
  31. API = "api"
  32. # The name of the router variable.
  33. ROUTER = "router"
  34. # The name of the socket variable.
  35. SOCKET = "socket"
  36. # The name of the variable to hold API results.
  37. RESULT = "result"
  38. # The name of the final variable.
  39. FINAL = "final"
  40. # The name of the process variable.
  41. PROCESSING = "processing"
  42. # The name of the state variable.
  43. STATE = "state"
  44. # The name of the events variable.
  45. EVENTS = "events"
  46. # The name of the initial hydrate event.
  47. HYDRATE = "hydrate"
  48. # The name of the is_hydrated variable.
  49. IS_HYDRATED = "is_hydrated"
  50. # The name of the function to add events to the queue.
  51. ADD_EVENTS = "addEvents"
  52. # The name of the var storing any connection error.
  53. CONNECT_ERROR = "connectErrors"
  54. # The name of the function for converting a dict to an event.
  55. TO_EVENT = "Event"
  56. # The name of the internal on_load event.
  57. ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
  58. # The name of the internal event to update generic state vars.
  59. UPDATE_VARS_INTERNAL = (
  60. "reflex___state____update_vars_internal_state.update_vars_internal"
  61. )
  62. # The name of the frontend event exception state
  63. FRONTEND_EXCEPTION_STATE = "reflex___state____frontend_event_exception_state"
  64. # The full name of the frontend exception state
  65. FRONTEND_EXCEPTION_STATE_FULL = (
  66. f"reflex___state____state.{FRONTEND_EXCEPTION_STATE}"
  67. )
  68. class PageNames(SimpleNamespace):
  69. """The name of basic pages deployed in NextJS."""
  70. # The name of the index page.
  71. INDEX_ROUTE = "index"
  72. # The name of the app root page.
  73. APP_ROOT = "_app"
  74. # The root stylesheet filename.
  75. STYLESHEET_ROOT = "__reflex_global_styles"
  76. # The name of the document root page.
  77. DOCUMENT_ROOT = "_document"
  78. # The name of the theme page.
  79. THEME = "theme"
  80. # The module containing components.
  81. COMPONENTS = "components"
  82. # The module containing shared stateful components
  83. STATEFUL_COMPONENTS = "stateful_components"
  84. class ComponentName(Enum):
  85. """Component names."""
  86. BACKEND = "Backend"
  87. FRONTEND = "Frontend"
  88. def zip(self):
  89. """Give the zip filename for the component.
  90. Returns:
  91. The lower-case filename with zip extension.
  92. """
  93. return self.value.lower() + Ext.ZIP
  94. class CompileContext(str, Enum):
  95. """The context in which the compiler is running."""
  96. RUN = "run"
  97. EXPORT = "export"
  98. DEPLOY = "deploy"
  99. UNDEFINED = "undefined"
  100. class Imports(SimpleNamespace):
  101. """Common sets of import vars."""
  102. EVENTS = {
  103. "react": [ImportVar(tag="useContext")],
  104. f"$/{Dirs.CONTEXTS_PATH}": [ImportVar(tag="EventLoopContext")],
  105. f"$/{Dirs.STATE_PATH}": [ImportVar(tag=CompileVars.TO_EVENT)],
  106. }
  107. class Hooks(SimpleNamespace):
  108. """Common sets of hook declarations."""
  109. EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
  110. AUTOFOCUS = """
  111. // Set focus to the specified element.
  112. const focusRef = useRef(null)
  113. useEffect(() => {
  114. if (focusRef.current) {
  115. focusRef.current.focus();
  116. }
  117. })"""
  118. class HookPosition(enum.Enum):
  119. """The position of the hook in the component."""
  120. INTERNAL = "internal"
  121. PRE_TRIGGER = "pre_trigger"
  122. POST_TRIGGER = "post_trigger"
  123. class MemoizationDisposition(enum.Enum):
  124. """The conditions under which a component should be memoized."""
  125. # If the component uses state or events, it should be memoized.
  126. STATEFUL = "stateful"
  127. ALWAYS = "always"
  128. NEVER = "never"
  129. @dataclasses.dataclass(frozen=True)
  130. class MemoizationMode:
  131. """The mode for memoizing a Component."""
  132. # The conditions under which the component should be memoized.
  133. disposition: MemoizationDisposition = MemoizationDisposition.STATEFUL
  134. # Whether children of this component should be memoized first.
  135. recursive: bool = True
  136. class SpecialAttributes(enum.Enum):
  137. """Special attributes for components.
  138. These are placed in custom_attrs and rendered as-is rather than converting
  139. to a style prop.
  140. """
  141. DATA_UNDERSCORE = "data_"
  142. DATA_DASH = "data-"
  143. ARIA_UNDERSCORE = "aria_"
  144. ARIA_DASH = "aria-"
  145. @classmethod
  146. def is_special(cls, attr: str) -> bool:
  147. """Check if the attribute is special.
  148. Args:
  149. attr: the attribute to check
  150. Returns:
  151. True if the attribute is special.
  152. """
  153. return any(attr.startswith(value.value) for value in cls)