165 lines
4.2 KiB
Python
165 lines
4.2 KiB
Python
"""Templates to use in the pynecone compiler."""
|
|
|
|
from typing import Optional, Set
|
|
|
|
from pynecone import constants
|
|
from pynecone.utils import join
|
|
|
|
# Template for the Pynecone config file.
|
|
PCCONFIG = f"""# The Pynecone configuration file.
|
|
|
|
APP_NAME = "{{app_name}}"
|
|
API_HOST = "http://localhost:8000"
|
|
BUN_PATH = "$HOME/.bun/bin/bun"
|
|
ENV = "{constants.Env.DEV.value}"
|
|
DB_URI = "sqlite:///{constants.DB_NAME}"
|
|
"""
|
|
|
|
# Javascript formatting.
|
|
CONST = "const {name} = {value}".format
|
|
PROP = "{object}.{property}".format
|
|
IMPORT_LIB = 'import "{lib}"'.format
|
|
IMPORT_FIELDS = 'import {default}{others} from "{lib}"'.format
|
|
|
|
|
|
def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None) -> str:
|
|
"""Format an import statement.
|
|
|
|
Args:
|
|
lib: The library to import from.
|
|
default: The default field to import.
|
|
rest: The set of fields to import from the library.
|
|
|
|
Returns:
|
|
The compiled import statement.
|
|
"""
|
|
# Handle the case of direct imports with no libraries.
|
|
if lib == "":
|
|
assert default == "", "No default field allowed for empty library."
|
|
assert rest is not None and len(rest) > 0, "No fields to import."
|
|
return join([IMPORT_LIB(lib=lib) for lib in sorted(rest)])
|
|
|
|
# Handle importing from a library.
|
|
rest = rest or set()
|
|
if len(default) == 0 and len(rest) == 0:
|
|
# Handle the case of importing a library with no fields.
|
|
return IMPORT_LIB(lib=lib)
|
|
else:
|
|
# Handle importing specific fields from a library.
|
|
others = f'{{{", ".join(sorted(rest))}}}' if len(rest) > 0 else ""
|
|
if len(default) > 0 and len(rest) > 0:
|
|
default += ", "
|
|
return IMPORT_FIELDS(default=default, others=others, lib=lib)
|
|
|
|
|
|
# Code to render a NextJS Document root.
|
|
DOCUMENT_ROOT = join(
|
|
[
|
|
"{imports}",
|
|
"export default function Document() {{",
|
|
"return (",
|
|
"{document}",
|
|
")",
|
|
"}}",
|
|
]
|
|
).format
|
|
|
|
# Template for the theme file.
|
|
THEME = "export default {theme}".format
|
|
|
|
# Code to render a single NextJS component.
|
|
COMPONENT = join(
|
|
[
|
|
"{imports}",
|
|
"{custom_code}",
|
|
"{constants}",
|
|
"export default function Component() {{",
|
|
"{state}",
|
|
"{events}",
|
|
"{effects}",
|
|
"return (",
|
|
"{render}",
|
|
")",
|
|
"}}",
|
|
]
|
|
).format
|
|
|
|
# React state declarations.
|
|
USE_STATE = CONST(
|
|
name="[{state}, {set_state}]", value="useState({initial_state})"
|
|
).format
|
|
|
|
|
|
def format_state_setter(state: str) -> str:
|
|
"""Format a state setter.
|
|
|
|
Args:
|
|
state: The name of the state variable.
|
|
|
|
Returns:
|
|
The compiled state setter.
|
|
"""
|
|
return f"set{state[0].upper() + state[1:]}"
|
|
|
|
|
|
def format_state(
|
|
state: str,
|
|
initial_state: str,
|
|
) -> str:
|
|
"""Format a state declaration.
|
|
|
|
Args:
|
|
state: The name of the state variable.
|
|
initial_state: The initial state of the state variable.
|
|
|
|
Returns:
|
|
The compiled state declaration.
|
|
"""
|
|
set_state = format_state_setter(state)
|
|
return USE_STATE(state=state, set_state=set_state, initial_state=initial_state)
|
|
|
|
|
|
# Events.
|
|
EVENT_ENDPOINT = constants.Endpoint.EVENT.name
|
|
EVENT_FN = join(
|
|
[
|
|
"const Event = events => {set_state}({{",
|
|
" ...{state},",
|
|
" events: [...{state}.events, ...events],",
|
|
"}})",
|
|
]
|
|
).format
|
|
|
|
|
|
# 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 () => {{",
|
|
f" if ({RESULT}.{STATE} != null) {{{{",
|
|
f" {{set_state}}({{{{",
|
|
f" ...{RESULT}.{STATE},",
|
|
f" events: [...{{state}}.{EVENTS}, ...{RESULT}.{EVENTS}],",
|
|
" }})",
|
|
f" {SET_RESULT}({{{{",
|
|
f" {STATE}: null,",
|
|
f" {EVENTS}: [],",
|
|
f" {PROCESSING}: false,",
|
|
" }})",
|
|
" }}",
|
|
f" await updateState({{state}}, {RESULT}, {SET_RESULT}, {EVENT_ENDPOINT}, {ROUTER})",
|
|
" }}",
|
|
" update()",
|
|
"}})",
|
|
]
|
|
).format
|
|
|
|
# Routing
|
|
ROUTER = f"const {constants.ROUTER} = useRouter()"
|