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.
@@ -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])
@@ -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")