-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathcompiler.py
More file actions
231 lines (179 loc) ยท 6.81 KB
/
compiler.py
File metadata and controls
231 lines (179 loc) ยท 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
"""Compiler variables."""
import dataclasses
import enum
from enum import Enum
from types import SimpleNamespace
from reflex_base.constants import Dirs
from reflex_base.utils.imports import ImportVar
# The prefix used to create setters for state vars.
SETTER_PREFIX = "set_"
# The file used to specify no compilation.
NOCOMPILE_FILE = "nocompile"
class Ext(SimpleNamespace):
"""Extension used in Reflex."""
# The extension for JS files.
JS = ".js"
# The extension for JSX files.
JSX = ".jsx"
# The extension for python files.
PY = ".py"
# The extension for css files.
CSS = ".css"
# The extension for zip files.
ZIP = ".zip"
# The extension for executable files on Windows.
EXE = ".exe"
# The extension for markdown files.
MD = ".md"
class CompileVars(SimpleNamespace):
"""The variables used during compilation."""
# The expected variable name where the rx.App is stored.
APP = "app"
# The expected variable name where the API object is stored for deployment.
API = "api"
# The name of the router variable.
ROUTER = "router"
# The name of the socket variable.
SOCKET = "socket"
# The name of the variable to hold API results.
RESULT = "result"
# The name of the final variable.
FINAL = "final"
# 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 is_hydrated variable.
IS_HYDRATED = "is_hydrated"
# The name of the function to add events to the queue.
ADD_EVENTS = "addEvents"
# The name of the function to apply event actions before invoking a target.
APPLY_EVENT_ACTIONS = "applyEventActions"
# The name of the var storing any connection error.
CONNECT_ERROR = "connectErrors"
# The name of the function for converting a dict to an event.
TO_EVENT = "ReflexEvent"
# The name of the internal on_load event.
ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
# The name of the internal event to update generic state vars.
UPDATE_VARS_INTERNAL = (
"reflex___state____update_vars_internal_state.update_vars_internal"
)
# The name of the frontend event exception state
FRONTEND_EXCEPTION_STATE = "reflex___state____frontend_event_exception_state"
# The full name of the frontend exception state
FRONTEND_EXCEPTION_STATE_FULL = (
f"reflex___state____state.{FRONTEND_EXCEPTION_STATE}"
)
class PageNames(SimpleNamespace):
"""The name of basic pages deployed in the frontend."""
# The name of the index page.
INDEX_ROUTE = "index"
# The name of the app root page.
APP_ROOT = "root.jsx"
# The root stylesheet filename.
STYLESHEET_ROOT = "__reflex_global_styles"
# The name of the document root page.
DOCUMENT_ROOT = "_document.js"
# The name of the theme page.
THEME = "theme"
# The module containing components.
COMPONENTS = "components"
# The module containing shared stateful components
STATEFUL_COMPONENTS = "stateful_components"
class Embed(SimpleNamespace):
"""Public artifacts for ``mount_target`` (embed) builds.
These paths form the host-page contract: a host script tag points at
``ENTRY_PATH`` (relative to the frontend origin), which loads the route
manifest at ``MANIFEST_FILE`` and dispatches into the embedded app. They
are intentionally stable across dev and prod so the same host HTML works
in both modes.
"""
# Host pages reference this path (e.g. ``<script src="/app/entry.client.js">``).
# In dev, Vite serves the source file at this URL; in prod, a shim emitted
# by ``_emit_stable_entry_bootloader`` re-exports the hashed Vite entry.
ENTRY_PATH = "app/entry.client.js"
# Embed-aware variant of the entry, swapped in only when ``mount_target``
# is set so non-embed builds remain byte-identical to the framework default.
ENTRY_EMBED_TEMPLATE = "app/entry.client.embed.js"
# Compile-time-emitted route manifest the embed entry imports at runtime.
MANIFEST_FILE = "__reflex_embed_manifest.js"
class ComponentName(Enum):
"""Component names."""
BACKEND = "Backend"
FRONTEND = "Frontend"
def zip(self):
"""Give the zip filename for the component.
Returns:
The lower-case filename with zip extension.
"""
return self.value.lower() + Ext.ZIP
class CompileContext(str, Enum):
"""The context in which the compiler is running."""
RUN = "run"
EXPORT = "export"
DEPLOY = "deploy"
UNDEFINED = "undefined"
class Imports(SimpleNamespace):
"""Common sets of import vars."""
EVENTS = {
"react": [ImportVar(tag="useContext")],
f"$/{Dirs.CONTEXTS_PATH}": [ImportVar(tag="EventLoopContext")],
f"$/{Dirs.STATE_PATH}": [
ImportVar(tag=CompileVars.TO_EVENT),
ImportVar(tag=CompileVars.APPLY_EVENT_ACTIONS),
],
}
class Hooks(SimpleNamespace):
"""Common sets of hook declarations."""
EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
class HookPosition(enum.Enum):
"""The position of the hook in the component."""
INTERNAL = "internal"
PRE_TRIGGER = "pre_trigger"
POST_TRIGGER = "post_trigger"
class MemoizationDisposition(enum.Enum):
"""The conditions under which a component should be memoized."""
# If the component uses state or events, it should be memoized.
STATEFUL = "stateful"
ALWAYS = "always"
NEVER = "never"
@dataclasses.dataclass(frozen=True)
class MemoizationMode:
"""The mode for memoizing a Component."""
# The conditions under which the component should be memoized.
disposition: MemoizationDisposition = MemoizationDisposition.STATEFUL
# Whether children of this component should be memoized first.
recursive: bool = True
DATA_UNDERSCORE = "data_"
DATA_DASH = "data-"
ARIA_UNDERSCORE = "aria_"
ARIA_DASH = "aria-"
SPECIAL_ATTRS = (
DATA_UNDERSCORE,
DATA_DASH,
ARIA_UNDERSCORE,
ARIA_DASH,
)
class SpecialAttributes(enum.Enum):
"""Special attributes for components.
These are placed in custom_attrs and rendered as-is rather than converting
to a style prop.
"""
@classmethod
def is_special(cls, attr: str) -> bool:
"""Check if the attribute is special.
Args:
attr: the attribute to check
Returns:
True if the attribute is special.
"""
return attr.startswith(SPECIAL_ATTRS)
class ResetStylesheet(SimpleNamespace):
"""Constants for CSS reset stylesheet."""
# The filename of the CSS reset file.
FILENAME = "__reflex_style_reset.css"