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

Closes: #39 Add a way to specify the position of child components. #70

Merged
merged 25 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d0e913a
feat(component.py,-dom_method,py,-parser.py,-parent.fyre,-store.fyre)…
SuelenKarbivnychyy Jul 27, 2023
af0e363
fix(dom_methods.py): handle a edge case when specifying position of c…
SuelenKarbivnychyy Jul 28, 2023
0c2f1bb
delete extra test
SuelenKarbivnychyy Aug 1, 2023
956d54c
feat(dom_methods.py,-store.fyre): deleted <pyml> from store.fyre and …
SuelenKarbivnychyy Aug 1, 2023
7937443
refactor(test_quote-folder): its just a test folder for better explan…
SuelenKarbivnychyy Aug 4, 2023
c7ab9d5
refactor(dom_methods.py-parser.py-component.py): update the code stru…
SuelenKarbivnychyy Aug 7, 2023
b8d1008
fix: parsing algo
sansyrox Aug 12, 2023
4d2ac7b
fix(parser.py): added support for new self.current_children list
SuelenKarbivnychyy Aug 15, 2023
bcbc8bc
fix(parser.py): fix the node order rendering
SuelenKarbivnychyy Aug 21, 2023
02006e1
fix(parser.py): Fixed node order rendering
SuelenKarbivnychyy Aug 21, 2023
73ba5d6
fix(Developed-a-way-of-adding-original-name-when-the-component-is-cre…
SuelenKarbivnychyy Aug 22, 2023
2dd127a
style(parser.py): reformat specific part of code
SuelenKarbivnychyy Aug 23, 2023
7d79a9b
refactor(component.py): refactor code
SuelenKarbivnychyy Aug 28, 2023
8616919
refactor: Merged files, fixed conflicts
SuelenKarbivnychyy Aug 28, 2023
ecf7897
deleted empty spaces
SuelenKarbivnychyy Aug 29, 2023
6efec43
fix(__init__.fyre): fixed a bug
SuelenKarbivnychyy Aug 29, 2023
6ad7037
test: add a testing application
sansyrox Aug 29, 2023
5c8212e
Merge branch 'sk-39' of https://github.com/SuelenKarbivnychyy/starfyr…
SuelenKarbivnychyy Aug 30, 2023
bdd93d7
fix(parser.py): Fixed order of slot compoments
SuelenKarbivnychyy Aug 31, 2023
76a9921
minor improvements
sansyrox Sep 1, 2023
e3c29ce
update the algo
sansyrox Sep 2, 2023
8e244a0
add parser explanation
sansyrox Sep 2, 2023
7b6da80
docs(parser.py): added comments
SuelenKarbivnychyy Sep 5, 2023
3e9fb64
refactor(parser.py): added a TODO
SuelenKarbivnychyy Sep 5, 2023
8e8000d
Update starfyre/parser.py
sansyrox Sep 7, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
8 changes: 7 additions & 1 deletion starfyre/component.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
SuelenKarbivnychyy marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

field is not needed

from typing import Any, Optional


Expand All @@ -18,13 +18,19 @@ class Component:
css: str = ""
js: str = ""
# on any property change, rebuild the tree
original_name: str = ""


def render(self):
pass

@property
def is_text_component(self):
return self.tag == "TEXT_NODE"

@property
def is_slot_component(self):
return self.tag == "slot"

def __repr__(self):
return f"<{self.tag}> {self.data} {self.children} </{self.tag}>"
6 changes: 5 additions & 1 deletion starfyre/dom_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def assign_event_listeners(event_listener_name, event_listener):
return html, js_event_listener


def render_helper(component: Component) -> tuple[str, str, str]:
def render_helper(component: Component) -> tuple[str, str, str]:
Copy link
Member

Choose a reason for hiding this comment

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

we should not add trailing space here

# Add event listeners
def is_listener(name):
return name.startswith("on")
Expand Down Expand Up @@ -91,9 +91,12 @@ def is_attribute(name):
if not component.is_text_component:
html += f"{prop_string} >"



# Render children
children = component.children
# childElements.forEach(childElement => render(childElement, dom));

for childElement in children:
childElement.parentElement = component
new_html, new_css, new_js = render_helper(childElement)
Expand All @@ -104,6 +107,7 @@ def is_attribute(name):
html += f"</{tag}>\n"

component.html = html

return html, css, js


Expand Down
71 changes: 51 additions & 20 deletions starfyre/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(self, component_local_variables, component_global_variables, css, j
self.css = css
self.js = js
self.root_node = None


# these are the event handlers and the props
self.local_variables = component_local_variables
Expand All @@ -38,6 +39,7 @@ def __init__(self, component_local_variables, component_global_variables, css, j
)
# populate the dict with the components
self.component_name = component_name
self.current_children = []

generic_tags = {
"html", "div", "p", "b", "span", "i", "button", "head", "link", "meta", "style", "title",
Expand All @@ -49,7 +51,7 @@ def __init__(self, component_local_variables, component_global_variables, css, j
"picture", "object", "portal", "svg", "math", "canvas", "script", "noscript", "caption",
"col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "datalist",
"fieldlist", "form", "input", "label", "legend", "meter", "optgroup", "option", "output",
"progress", "select", "textarea", "details", "dialog", "summary"
"progress", "select", "textarea", "details", "dialog", "summary", "slot"
}


Expand Down Expand Up @@ -104,13 +106,16 @@ def handle_starttag(self, tag, attrs):
# if the tag is not found in the generic tags but found in custom components
if tag not in self.generic_tags and tag in self.components:
component = self.components[tag]
tag = component.tag
component.original_name = tag
component.props = {**component.props, **props}
component.state = {**component.state, **state}

component.event_listeners = {**component.event_listeners, **event_listeners}
self.stack.append(component)

print("This is the stack", self.stack)
#SK TODO: Bug - we should check for if self.root_node is None:
if self.root_node is None:
self.root_node = component
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should check if self.root_node is None.

sansyrox marked this conversation as resolved.
Show resolved Hide resolved
return

# if the tag is not found in the generic tags and custom components
Expand Down Expand Up @@ -144,6 +149,7 @@ def handle_starttag(self, tag, attrs):
# instead of assiging tags we assign uuids

self.stack.append(component)
pass
sansyrox marked this conversation as resolved.
Show resolved Hide resolved


def handle_endtag(self, tag):
Expand All @@ -154,21 +160,47 @@ def handle_endtag(self, tag):
# we need to check if the tag is a default component or a custom component
# if it is a custom component, we get the element from the custom components dict

if tag not in self.generic_tags and tag in self.components:
component = self.components[tag]
tag = component.tag


endtag_node = self.stack.pop()
self.current_depth -= 1

# Now, we check if `self.children` contains a slot component. If it does, we need to replace the slot component with the children of the slot component.
# @Suelen can you take this forward from here?
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
if endtag_node.tag != "style" and endtag_node.tag != "script":
if len(self.stack) > 0:
parent_node = self.stack[-1] #this is last item/"top element" of stack
parent_node.children.append(endtag_node)
if endtag_node.original_name != "": #this node is for "custom" component, so we should check for <slot> tags
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
#process endtag_node children
new_children = []
for child_component in endtag_node.children:
if child_component.tag == "slot":
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
new_children.extend(self.current_children)
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't it be the other way round ?

self.children.extend(new_children)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

shouldn't it be the other way round ?

self.children.extend(new_children)?

No. new_children is a copy of endtag_node.children with <slot> replaced by self.current_children.

else:
new_children.append(child_component)
endtag_node.children = new_children
self.current_children = []
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I defined new_children list to hold the list of current children of endtag_node with slot elements replaced by content of self.current_children, then assigned new_children list as children of endtag_node.



# if parent_node.original_name == endtag_node.original_name: #SK Why we need this condition? It is empty string by default
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
# parent_node.children.extend(self.current_children)
# self.current_children = []
# else:
# self.current_children.append(endtag_node)
#SK : New code
self.current_children.append(endtag_node)

# if parent_node.is_custom: #Checking if the parent node is the special custom tag
# endtag_node.is_slot_element = True
else:
parent_node = endtag_node
self.root_node = endtag_node

self.root_node.children.extend(self.current_children)
self.current_children = []

pass

print("test end")


def is_signal(self, str):
if not str:
Expand All @@ -192,7 +224,7 @@ def handle_data(self, data):

# parsing starts here
state = {}
parent_node = self.stack[-1]
# parent_node = self.stack[-1]

uuid = uuid4()
component_signal = ""
Expand Down Expand Up @@ -220,7 +252,8 @@ def handle_data(self, data):
match, self.local_variables, self.global_variables
)
if isinstance(eval_result, Component):
self.stack[-1].children.append(eval_result)
# this is a parent, right?
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
self.children.append(eval_result) #TODO: Check with sanskar - this is a bug, we don't have self.children
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
sansyrox marked this conversation as resolved.
Show resolved Hide resolved
return
elif isinstance(eval_result, str):
current_data = eval_result
Expand Down Expand Up @@ -280,15 +313,13 @@ def handle_data(self, data):
)
)

parent_node.children.append(wrapper_div_component)

print(
"parent node",
parent_node.tag,
parent_node.children,
"for the text node ",
data,
)
# self.children.append(wrapper_div_component)
if len(self.stack) > 0:
parent_node = self.stack[-1]
parent_node.children.append(wrapper_div_component)
else:
self.current_children.append(wrapper_div_component)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It still breaks the order in case we have complex structure with nodes inside one another... I'm current looking for a solution.

sansyrox marked this conversation as resolved.
Show resolved Hide resolved


def get_stack(self):
return self.stack
Expand Down
2 changes: 1 addition & 1 deletion test-application/__init__.fyre
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async def handle_on_click(e):

<style>
body {
background-color: red;
background-color: green;
}
</style>

Expand Down
2 changes: 1 addition & 1 deletion test-application/css_file_test.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.import_test {
padding-top: 10%;
}
}
22 changes: 11 additions & 11 deletions test-application/parent.fyre
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@ def ssr_request():
return "No response"

<pyml>
<span>

<div>
<h1> THIS IS MY FIRST HTML NODE </h1>
{ssr_request()}
<p> THIS IS MY SECOND HTML NODE </p>
<span>
<div>
<h2> 1 This is just a test </h2>
<p> 2 HTML NODE </p>
{ssr_request()}
<p> 3 HTML NODE </p>
{ssr_request()}
</div>
<b>
{use_parent_signal()}
</b>
<b>
{get_parent_signal()}
</b>
<slot></slot>
<ul>
<li>a</li>
<li>a</li>
Copy link
Member

Choose a reason for hiding this comment

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

extra spaces

<li>b</li>
<li>c</li>
<li>c</li>
Copy link
Member

Choose a reason for hiding this comment

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

same

</ul>
<div>
This won't be re-rendered
</div>

This won't be re-rendered
</div>
</span>
</pyml>
8 changes: 8 additions & 0 deletions test-quote/__init__.fyre
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .daily_quote import daily_quote


<pyml>
<daily_quote hello='world'>
<p> Is a beautiful day </p>
</daily_quote>
</pyml>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

And here __init__.fyre is our app, and it’s making usage of our daily_quote.fyre component.

<daily_quote> tag is not in our generic_tags set, (ref, parser.py line 43 and lines 106...108 on handle_starttag function), “meaning that <daily_quote> is a custom component on __init__.fyre” and whatever inner_content we have inside <daily_quote>, we want to place it instead of the <slot> tag " on the final hmtl file.

That is why we need the inner_content list, because this content is not “normal children”, this content is what we want to add to our code in place of the <slot>.
If I keep adding this “inner content of our custom component <daily_quote>” to the regular children list, we will have no way of telling what are the “children components aka inner_content” we want to replace the <slot> tag with.

Then on the handle_endtag function we check if the parente_node is a custom component, (ref, parse.py line 168 ...171) and we are able to do this check here because we had the is_custom property set up to be True or False on the handle_starttag function.
If the parent_node is is_custom == True then we need to save this parent_node children to inner_content list where later on we will replace the <slot> with.
<slot> is not a custom tag, <slot> is a generic tag, kinda like a placeholder for us to know that whenever we have <slot> on our component definition aka daily_quote.fyre is where we will add the <inner_content> of our custom component usage aka what is defined in __init__.fyre

And this will be the final html file after transpiler.
image

8 changes: 8 additions & 0 deletions test-quote/daily_quote.fyre
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<pyml>
<b>
You
<p> Are </p>
Awesome
<slot>This is slot</slot>
</b>
</pyml>