hypie 0.1.1.dev2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hypie/__init__.py +34 -0
- hypie/cli/build_components.py +148 -0
- hypie/commands.py +220 -0
- hypie/dom_position.py +39 -0
- hypie/events.py +77 -0
- hypie/experimental/client_components.py +78 -0
- hypie/experimental/components.py +135 -0
- hypie/experimental/hyperscript.py +35 -0
- hypie/experimental/templates.py +50 -0
- hypie/features.py +46 -0
- hypie/hs_ast/commands.py +478 -0
- hypie/hs_ast/constants.py +1 -0
- hypie/hs_ast/contexts.py +3 -0
- hypie/hs_ast/expressions.py +719 -0
- hypie/hs_ast/features.py +181 -0
- hypie/hs_ast/helpers.py +85 -0
- hypie/literals.py +76 -0
- hypie-0.1.1.dev2.dist-info/METADATA +816 -0
- hypie-0.1.1.dev2.dist-info/RECORD +22 -0
- hypie-0.1.1.dev2.dist-info/WHEEL +4 -0
- hypie-0.1.1.dev2.dist-info/entry_points.txt +3 -0
- hypie-0.1.1.dev2.dist-info/licenses/LICENSE +7 -0
hypie/hs_ast/features.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from typing import Iterable, Literal
|
|
2
|
+
from textwrap import indent, dedent
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from hypie.hs_ast.constants import INDENT
|
|
6
|
+
from hypie.hs_ast.commands import Command
|
|
7
|
+
from hypie.hs_ast.expressions import *
|
|
8
|
+
from hypie.hs_ast import helpers
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Feature:
|
|
12
|
+
def render(self): ...
|
|
13
|
+
def __html__(self):
|
|
14
|
+
return self.render()
|
|
15
|
+
|
|
16
|
+
# __html__ = __str__
|
|
17
|
+
__str__ = __html__
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class InitF(Feature):
|
|
22
|
+
commands: tuple[Command] = None
|
|
23
|
+
immediately: bool = False
|
|
24
|
+
|
|
25
|
+
def __getitem__(self, commands):
|
|
26
|
+
if not isinstance(commands, Iterable):
|
|
27
|
+
commands = (commands,)
|
|
28
|
+
# self.commands = commands
|
|
29
|
+
return InitF(
|
|
30
|
+
commands=[
|
|
31
|
+
c for c in helpers.flatten_iterable(commands) if isinstance(c, Command)
|
|
32
|
+
],
|
|
33
|
+
immediately=self.immediately,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def render(self):
|
|
37
|
+
lines = []
|
|
38
|
+
header = "init" + (" immediately" if self.immediately else "")
|
|
39
|
+
lines.append(header)
|
|
40
|
+
end = "end"
|
|
41
|
+
for c in self.commands:
|
|
42
|
+
lines.append(indent(c.render(), INDENT, lambda _: True))
|
|
43
|
+
lines.append(end)
|
|
44
|
+
return "\n".join(lines)
|
|
45
|
+
|
|
46
|
+
def __call__(self, immediately: bool = False):
|
|
47
|
+
return InitF(immediately=immediately)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
type ON_QUEUE = Literal["none", "all", "first", "last", "concurrent"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class OnF(Feature):
|
|
55
|
+
event_specs: tuple[str | EventSpecLiteral]
|
|
56
|
+
queue: ON_QUEUE = None
|
|
57
|
+
commands: tuple[Command] = None
|
|
58
|
+
finally_commands: tuple[Command] = None
|
|
59
|
+
|
|
60
|
+
def __getitem__(self, commands):
|
|
61
|
+
if not isinstance(commands, Iterable):
|
|
62
|
+
commands = (commands,)
|
|
63
|
+
self.commands = [
|
|
64
|
+
c for c in helpers.flatten_iterable(commands) if isinstance(c, Command)
|
|
65
|
+
]
|
|
66
|
+
# print("ON FEATURE GOT COMMANDS: ", self.commands)
|
|
67
|
+
return self
|
|
68
|
+
|
|
69
|
+
def render(self):
|
|
70
|
+
header = "on"
|
|
71
|
+
events = []
|
|
72
|
+
for e in self.event_specs:
|
|
73
|
+
events.append(e.render() if isinstance(e, Expr) else e)
|
|
74
|
+
header += f" {'\nor '.join(events)}"
|
|
75
|
+
if self.queue == "concurrent":
|
|
76
|
+
header = "every " + header
|
|
77
|
+
elif self.queue:
|
|
78
|
+
header += f"\nqueue {self.queue}"
|
|
79
|
+
lines = []
|
|
80
|
+
lines.append(header)
|
|
81
|
+
# print("LOOPING OVER: ", self.commands)
|
|
82
|
+
for c in self.commands:
|
|
83
|
+
lines.append(indent(c.render(), INDENT, lambda _: True))
|
|
84
|
+
if self.finally_commands:
|
|
85
|
+
lines.append("finally")
|
|
86
|
+
for c in self.finally_commands:
|
|
87
|
+
lines.append(indent(c.render(), INDENT, lambda _: True))
|
|
88
|
+
lines.append("end")
|
|
89
|
+
return "\n".join(lines)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def Finally(self):
|
|
93
|
+
return _Finally(self)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class _Finally:
|
|
98
|
+
feature: Feature
|
|
99
|
+
|
|
100
|
+
def __getitem__(self, commands):
|
|
101
|
+
if not isinstance(commands, Iterable):
|
|
102
|
+
commands = (commands,)
|
|
103
|
+
self.feature.finally_commands = [
|
|
104
|
+
c for c in helpers.flatten_iterable(commands) if isinstance(c, Command)
|
|
105
|
+
]
|
|
106
|
+
return self.feature
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class LiveF(Feature):
|
|
111
|
+
commands: tuple[Command] = None
|
|
112
|
+
|
|
113
|
+
def __getitem__(self, commands):
|
|
114
|
+
if not isinstance(commands, Iterable):
|
|
115
|
+
commands = (commands,)
|
|
116
|
+
# self.commands = commands
|
|
117
|
+
return LiveF(
|
|
118
|
+
commands=[
|
|
119
|
+
c for c in helpers.flatten_iterable(commands) if isinstance(c, Command)
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def render(self):
|
|
124
|
+
lines = []
|
|
125
|
+
header = "live"
|
|
126
|
+
lines.append(header)
|
|
127
|
+
end = "end"
|
|
128
|
+
for c in self.commands:
|
|
129
|
+
lines.append(indent(c.render(), INDENT, lambda _: True))
|
|
130
|
+
lines.append(end)
|
|
131
|
+
return "\n".join(lines)
|
|
132
|
+
|
|
133
|
+
def __call__(self):
|
|
134
|
+
return LiveF()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass
|
|
138
|
+
class WhenF(Feature):
|
|
139
|
+
exprs: tuple[Expr] = None
|
|
140
|
+
commands: tuple[Command] = None
|
|
141
|
+
|
|
142
|
+
def __getitem__(self, commands):
|
|
143
|
+
if not isinstance(commands, Iterable):
|
|
144
|
+
commands = (commands,)
|
|
145
|
+
self.commands = [
|
|
146
|
+
c for c in helpers.flatten_iterable(commands) if isinstance(c, Command)
|
|
147
|
+
]
|
|
148
|
+
return self
|
|
149
|
+
|
|
150
|
+
def render(self):
|
|
151
|
+
header = "when"
|
|
152
|
+
parts = []
|
|
153
|
+
for e in self.exprs:
|
|
154
|
+
parts.append(e.render())
|
|
155
|
+
header += " " + "\nor ".join(parts) + " changes"
|
|
156
|
+
lines = [header]
|
|
157
|
+
for c in self.commands:
|
|
158
|
+
lines.append(indent(c.render(), INDENT, lambda _: True))
|
|
159
|
+
lines.append("end")
|
|
160
|
+
return "\n".join(lines)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@dataclass
|
|
164
|
+
class BindF(Feature):
|
|
165
|
+
exprA: Expr
|
|
166
|
+
exprB: Expr
|
|
167
|
+
|
|
168
|
+
def render(self):
|
|
169
|
+
return f"bind {self.exprA.render()} to {self.exprB.render()}"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class JsF(Feature):
|
|
174
|
+
javascript: str
|
|
175
|
+
|
|
176
|
+
def render(self):
|
|
177
|
+
header = "js"
|
|
178
|
+
end = "end"
|
|
179
|
+
js = dedent(self.javascript.strip("\n"))
|
|
180
|
+
|
|
181
|
+
return "\n".join([header, indent(js, INDENT, lambda _: True), end])
|
hypie/hs_ast/helpers.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Iterable
|
|
3
|
+
import htpy
|
|
4
|
+
from hypie.hs_ast.expressions import Expr
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def flatten_iterable(iterable):
|
|
8
|
+
if not isinstance(iterable, Iterable):
|
|
9
|
+
return [iterable]
|
|
10
|
+
out = []
|
|
11
|
+
for i in iterable:
|
|
12
|
+
out.extend(flatten_iterable(i))
|
|
13
|
+
return out
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def kebab_case_name(name):
|
|
17
|
+
return re.sub(r"(?<!^)([A-Z])", r"-\1", name).lower()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def htpy_to_tree(el: htpy.Element):
|
|
21
|
+
if isinstance(el, htpy.Fragment):
|
|
22
|
+
element_type = "_fragment"
|
|
23
|
+
nodes = el._node or []
|
|
24
|
+
children = []
|
|
25
|
+
attrs = ""
|
|
26
|
+
elif not isinstance(el, htpy.Element) and not hasattr(el, "_hs_dsl_component"):
|
|
27
|
+
return el
|
|
28
|
+
# print(type(el))
|
|
29
|
+
else:
|
|
30
|
+
if hasattr(el, "_hs_dsl_component") and el._hs_dsl_component == True:
|
|
31
|
+
print("found component")
|
|
32
|
+
try:
|
|
33
|
+
el = el.__html__()
|
|
34
|
+
except TypeError:
|
|
35
|
+
el = el().__html__()
|
|
36
|
+
nodes = getattr(el, "_children", [])
|
|
37
|
+
children = []
|
|
38
|
+
element_type = el._name
|
|
39
|
+
attrs = el._attrs
|
|
40
|
+
tree = {element_type: {"children": children, "attrs": attrs}}
|
|
41
|
+
# print(tree)
|
|
42
|
+
# if hasattr(el, "_children") and el._children:
|
|
43
|
+
if (
|
|
44
|
+
nodes is None
|
|
45
|
+
or isinstance(nodes, (htpy.Element, str, int, float, bool, Expr))
|
|
46
|
+
or hasattr(nodes, "_hs_dsl_component")
|
|
47
|
+
):
|
|
48
|
+
children.append(htpy_to_tree(nodes))
|
|
49
|
+
else:
|
|
50
|
+
for c in nodes:
|
|
51
|
+
# print(type(c))
|
|
52
|
+
children.append(htpy_to_tree(c))
|
|
53
|
+
return tree
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def tranform_tree(tree: dict, rules: dict):
|
|
57
|
+
# print(tree)
|
|
58
|
+
if isinstance(tree, str):
|
|
59
|
+
# print(tree)
|
|
60
|
+
if rules.get("text"):
|
|
61
|
+
tree = rules["text"](tree)
|
|
62
|
+
return tree
|
|
63
|
+
elif not isinstance(tree, dict):
|
|
64
|
+
return tree
|
|
65
|
+
new_tree = {}
|
|
66
|
+
k, v = next(iter(tree.items()))
|
|
67
|
+
new_tree[k] = {
|
|
68
|
+
"attrs": v["attrs"],
|
|
69
|
+
"children": [tranform_tree(c, rules) for c in v["children"]],
|
|
70
|
+
}
|
|
71
|
+
return new_tree
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def tree_to_htpy(tree):
|
|
75
|
+
if not isinstance(tree, dict):
|
|
76
|
+
return tree
|
|
77
|
+
k, v = next(iter(tree.items()))
|
|
78
|
+
children = []
|
|
79
|
+
for c in v["children"]:
|
|
80
|
+
children.append(tree_to_htpy(c))
|
|
81
|
+
return (
|
|
82
|
+
htpy.Element(k, children=children, attrs_str=v["attrs"])
|
|
83
|
+
if k != "_fragment"
|
|
84
|
+
else htpy.fragment[children]
|
|
85
|
+
)
|
hypie/literals.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from hypie.hs_ast.expressions import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def id(id_: str, /):
|
|
7
|
+
return IdDOMLiteral(id_=str(id_).lstrip("#"))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def cls(class_: str, /):
|
|
11
|
+
return ClassDOMLiteral(class_=str(class_).lstrip("."))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def q(query: str, /):
|
|
15
|
+
if query.startswith(">"):
|
|
16
|
+
query = query[1:]
|
|
17
|
+
if query.endswith("/>"):
|
|
18
|
+
query = query[:-2]
|
|
19
|
+
return QueryDOMLiteral(query=query)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def attr(attr_name, attr_value=None, /):
|
|
23
|
+
return AttrLiteral(attr_name=attr_name, attr_value=attr_value)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def var(symbol: str, /):
|
|
27
|
+
return VariableLiteral(symbol=symbol)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def t(value: str, /):
|
|
31
|
+
return TemplateLiteral(value=value)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def time(time: int, resolution: TIME_RES = "ms", /):
|
|
35
|
+
return TimeLiteral(time=time, resolution=resolution)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def event(event_name: str, /, bind: dict[str, Expr] = None):
|
|
39
|
+
return EventLiteral(event_name=event_name, bind=bind)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def event_spec(
|
|
43
|
+
event_name: str,
|
|
44
|
+
args: list[str] = None,
|
|
45
|
+
filter: Expr = None,
|
|
46
|
+
count: int = None,
|
|
47
|
+
from_: Expr | Literal["elsewhere"] = None,
|
|
48
|
+
in_: Expr = None,
|
|
49
|
+
debounce: TimeLiteral = None,
|
|
50
|
+
throttle: TimeLiteral = None,
|
|
51
|
+
):
|
|
52
|
+
if isinstance(event_name, Enum):
|
|
53
|
+
event_name = event_name.value
|
|
54
|
+
return EventSpecLiteral(
|
|
55
|
+
event_name=event_name,
|
|
56
|
+
args=args,
|
|
57
|
+
filter=filter,
|
|
58
|
+
count=count,
|
|
59
|
+
from_=from_,
|
|
60
|
+
in_=in_,
|
|
61
|
+
debounce=debounce,
|
|
62
|
+
throttle=throttle,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def as_type(expr: Expr, t: Literal["JSON", "JSONString"], /):
|
|
67
|
+
return AsType(expr, type=t)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# magic values
|
|
71
|
+
me = var("me")
|
|
72
|
+
I = var("I")
|
|
73
|
+
my = var("my")
|
|
74
|
+
result = var("result")
|
|
75
|
+
it = var("it")
|
|
76
|
+
body = var("body")
|