Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: handle routing for starfyre #67

Merged
merged 13 commits into from
Aug 25, 2023
577 changes: 419 additions & 158 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ requests = "^2.29.0"
[tool.poetry.group.dev.dependencies]
ruff = "^0.0.263"
black = "^23.3.0"
commitizen = "^3.5.3"

[build-system]
requires = ["poetry-core"]
Expand Down
11 changes: 9 additions & 2 deletions starfyre/__main__.py
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from starfyre import compile
from pathlib import Path
from .file_router import FileRouter
DeleMike marked this conversation as resolved.
Show resolved Hide resolved

import sys
import os
import shutil
Expand Down Expand Up @@ -74,12 +76,17 @@ def main(path, build):
if build:
# Compile and build project
init_file_path = absolute_path / "__init__.py"

# Note: The routes specified in the pages folder will have generated code in the build directory.
compile(init_file_path.resolve())

# At this point, the project has been compiled and the build directory has been created.
# Now, initialize the Router object and use it to handle file-based routing.
# Basically, generate the html files for the routes
router = FileRouter(absolute_path / "pages")
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
router.generate_routes()

# But there is no main file in the build directory.
create_main_file(str(absolute_path))

# Start/run project
subprocess.run(
[sys.executable, "-m", "build"],
Expand Down
11 changes: 8 additions & 3 deletions starfyre/compiler.py
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@

def get_fyre_files(project_dir):
fyre_files = []
for file in os.listdir(project_dir):
if file.endswith(".fyre"):
fyre_files.append(file)
for entry in os.listdir(project_dir):
if entry.endswith(".fyre"):
fyre_files.append(entry)
# check inside the 'pages' folder
if entry == 'pages':
for file_ in os.listdir(project_dir / "pages"):
if file_.endswith(".fyre"):
fyre_files.append(f'pages/{file_}')
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
return fyre_files


Expand Down
3 changes: 2 additions & 1 deletion starfyre/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ class UnknownTagError(Exception):
Attributes:
message (str): A description of the error.
"""
pass
def __init__(self, message='Unknown tag found.'):
super().__init__(message)
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
106 changes: 106 additions & 0 deletions starfyre/file_router.py
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from starfyre import create_component, render
sansyrox marked this conversation as resolved.
Show resolved Hide resolved

import os
import sys
from pathlib import Path
import importlib


class FileRouter:
"""
A router that handles file-based routing.

This router parses the specified pages directory to automatically generate routes based on
the file names. Each file in the pages directory is treated as a separate route.

Parameters:
pages_directory (str): The path to the directory containing the pages files.
Example:
pages_directory = "test-application/pages"
file_router = FileRouter(pages_directory)
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring should be a part of the __init__ function, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I'm not sure if I understand this question well.

I added docstrings to the missing __init__ function.

The docstring below

class FileRouter:

is for the class FileRouter.

Do you mean I should take all the docstring below that class inside the __iniy__ function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes


def __init__(self, pages_directory):
self.pages_directory = pages_directory


def generate_routes(self):
"""
Generate routes and create corresponding HTML files.
DeleMike marked this conversation as resolved.
Show resolved Hide resolved

This method generates routes based on the file names in the specified pages directory. Each file in the
pages directory with a ".fyre" extension is considered a separate route. The route names are derived from
the file names by removing the ".fyre" extension and converting the names to lowercase.

The generated route names are stored in a list, and corresponding HTML files are created in the specified
"dist" directory. The HTML files are created by transpiling the components using the `_build_output` method.

Note:
- This method should be called after initializing the `FileRouter` object.
- The `_build_output` method is responsible for generating the HTML files.

Example:
pages_directory = "test_app/pages"
router = FileRouter(pages_directory)
router.generate_routes() # This generates the routes and corresponding HTML files.

Raises:
FileNotFoundError: If the specified pages directory does not exist.
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
"""
routes = []
dist_dir = Path(self.pages_directory / ".." / "dist").resolve()
if not dist_dir.exists():
dist_dir.mkdir()

# get file names in the "pages" directory
for file_name in os.listdir(self.pages_directory):
if file_name.endswith(".fyre"):
route_name = file_name.replace(".fyre", "").lower()
routes.append(route_name)
# print(f'Found fyre file: New route will be = {route_name}')
# print(f'file path for route is = {dist_dir}/{route_name}.html')

# read the contents from the generated python files
self._build_output(generated_routes=routes, out_dir=dist_dir)


def _build_output(self, generated_routes, out_dir):
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
"""
Transpile the output of `render(component)` to route HTML files.

This method takes a list of generated routes and an output directory and transpiles the components
using `render(component)`. The resulting components are then written to corresponding HTML files
in the output directory.

Parameters:
generated_routes (list): A list of route names (strings) generated from the pages directory.
out_dir (str): The path to the output directory where the HTML files will be written.

Example:
pages_directory = "test_app/pages"
router = FileRouter(pages_directory)
router.generate_routes() # This generates the `generated_routes` list.
out_directory = "test_app/dist"
router._build_output(generated_routes, out_directory)
"""
print(f'Generated routes: {generated_routes}')

root = Path(out_dir / "..").resolve()
app_name = (str(root).split('/'))[-1] # get the user defined project name

for route_name in generated_routes:
# Get the module name dynamically based on the route_name
module_name = f"{Path(app_name)}.build.{route_name}"

try:
module = importlib.import_module(module_name)
except ModuleNotFoundError:
print(f"Error: Could not import module '{module_name}'.")
continue

component = module.__dict__[route_name]
result = str(render(component))

# write to component file
with open(out_dir / f"{route_name}.html", "w") as html_file:
html_file.write(result)
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
DeleMike marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
3 changes: 3 additions & 0 deletions test-application/pages/css_file_test.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.import_test {
padding-top: 10%;
}
8 changes: 8 additions & 0 deletions test-application/pages/home.fyre
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "./css_file_test.css"

def mocked_request():
return "fetched on the server"

<pyml>
<p class="import_test">Hello, World!</p>
</pyml>