templates.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """Templates to use in the pynecone compiler."""
  2. from typing import Optional, Set
  3. from pynecone import constants
  4. from pynecone.utils import join
  5. # Template for the Pynecone config file.
  6. PCCONFIG = f"""import pynecone as pc
  7. config = pc.Config(
  8. app_name="{{app_name}}",
  9. bun_path="{constants.BUN_PATH}",
  10. db_url="{constants.DB_URL}",
  11. env=pc.Env.DEV,
  12. )
  13. """
  14. # Javascript formatting.
  15. CONST = "const {name} = {value}".format
  16. PROP = "{object}.{property}".format
  17. IMPORT_LIB = 'import "{lib}"'.format
  18. IMPORT_FIELDS = 'import {default}{others} from "{lib}"'.format
  19. def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None) -> str:
  20. """Format an import statement.
  21. Args:
  22. lib: The library to import from.
  23. default: The default field to import.
  24. rest: The set of fields to import from the library.
  25. Returns:
  26. The compiled import statement.
  27. """
  28. # Handle the case of direct imports with no libraries.
  29. if lib == "":
  30. assert default == "", "No default field allowed for empty library."
  31. assert rest is not None and len(rest) > 0, "No fields to import."
  32. return join([IMPORT_LIB(lib=lib) for lib in sorted(rest)])
  33. # Handle importing from a library.
  34. rest = rest or set()
  35. if len(default) == 0 and len(rest) == 0:
  36. # Handle the case of importing a library with no fields.
  37. return IMPORT_LIB(lib=lib)
  38. else:
  39. # Handle importing specific fields from a library.
  40. others = f'{{{", ".join(sorted(rest))}}}' if len(rest) > 0 else ""
  41. if len(default) > 0 and len(rest) > 0:
  42. default += ", "
  43. return IMPORT_FIELDS(default=default, others=others, lib=lib)
  44. # Code to render a NextJS Document root.
  45. DOCUMENT_ROOT = join(
  46. [
  47. "{imports}",
  48. "export default function Document() {{",
  49. "return (",
  50. "{document}",
  51. ")",
  52. "}}",
  53. ]
  54. ).format
  55. # Template for the theme file.
  56. THEME = "export default {theme}".format
  57. # Code to render a single NextJS component.
  58. COMPONENT = join(
  59. [
  60. "{imports}",
  61. "{custom_code}",
  62. "{constants}",
  63. "export default function Component() {{",
  64. "{state}",
  65. "{events}",
  66. "{effects}",
  67. "return (",
  68. "{render}",
  69. ")",
  70. "}}",
  71. ]
  72. ).format
  73. # React state declarations.
  74. USE_STATE = CONST(
  75. name="[{state}, {set_state}]", value="useState({initial_state})"
  76. ).format
  77. def format_state_setter(state: str) -> str:
  78. """Format a state setter.
  79. Args:
  80. state: The name of the state variable.
  81. Returns:
  82. The compiled state setter.
  83. """
  84. return f"set{state[0].upper() + state[1:]}"
  85. def format_state(
  86. state: str,
  87. initial_state: str,
  88. ) -> str:
  89. """Format a state declaration.
  90. Args:
  91. state: The name of the state variable.
  92. initial_state: The initial state of the state variable.
  93. Returns:
  94. The compiled state declaration.
  95. """
  96. set_state = format_state_setter(state)
  97. return USE_STATE(state=state, set_state=set_state, initial_state=initial_state)
  98. # Events.
  99. EVENT_ENDPOINT = constants.Endpoint.EVENT.name
  100. EVENT_FN = join(
  101. [
  102. "const Event = events => {set_state}({{",
  103. " ...{state},",
  104. " events: [...{state}.events, ...events],",
  105. "}})",
  106. ]
  107. ).format
  108. # Effects.
  109. ROUTER = constants.ROUTER
  110. RESULT = constants.RESULT
  111. PROCESSING = constants.PROCESSING
  112. STATE = constants.STATE
  113. EVENTS = constants.EVENTS
  114. SET_RESULT = format_state_setter(RESULT)
  115. USE_EFFECT = join(
  116. [
  117. "useEffect(() => {{",
  118. " const update = async () => {{",
  119. f" if ({RESULT}.{STATE} != null) {{{{",
  120. f" {{set_state}}({{{{",
  121. f" ...{RESULT}.{STATE},",
  122. f" events: [...{{state}}.{EVENTS}, ...{RESULT}.{EVENTS}],",
  123. " }})",
  124. f" {SET_RESULT}({{{{",
  125. f" {STATE}: null,",
  126. f" {EVENTS}: [],",
  127. f" {PROCESSING}: false,",
  128. " }})",
  129. " }}",
  130. f" await updateState({{state}}, {RESULT}, {SET_RESULT}, {EVENT_ENDPOINT}, {ROUTER})",
  131. " }}",
  132. " update()",
  133. "}})",
  134. ]
  135. ).format
  136. # Routing
  137. ROUTER = f"const {constants.ROUTER} = useRouter()"