mayu-live 0.0.0

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.
Files changed (204) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +661 -0
  3. data/README.md +598 -0
  4. data/exe/mayu +33 -0
  5. data/lib/mayu/app_metrics.rb +93 -0
  6. data/lib/mayu/banner.rb +12 -0
  7. data/lib/mayu/client/README.md +17 -0
  8. data/lib/mayu/client/dist/DecompressionStreamPolyfill-3ceba43e.js +1 -0
  9. data/lib/mayu/client/dist/DecompressionStreamPolyfill-3ceba43e.js.br +0 -0
  10. data/lib/mayu/client/dist/DecompressionStreamPolyfill-3ceba43e.js.map +1 -0
  11. data/lib/mayu/client/dist/DecompressionStreamPolyfill-3ceba43e.js.map.br +0 -0
  12. data/lib/mayu/client/dist/custom-elements/mayu-alert-cd7ad2a4.js +1 -0
  13. data/lib/mayu/client/dist/custom-elements/mayu-alert-cd7ad2a4.js.map +1 -0
  14. data/lib/mayu/client/dist/custom-elements/mayu-disconnected-9f349f46.js +1 -0
  15. data/lib/mayu/client/dist/custom-elements/mayu-disconnected-9f349f46.js.map +1 -0
  16. data/lib/mayu/client/dist/custom-elements/mayu-exception-63df4e8c.js +1 -0
  17. data/lib/mayu/client/dist/custom-elements/mayu-exception-63df4e8c.js.map +1 -0
  18. data/lib/mayu/client/dist/custom-elements/mayu-ping-c498c2a6.js +1 -0
  19. data/lib/mayu/client/dist/custom-elements/mayu-ping-c498c2a6.js.map +1 -0
  20. data/lib/mayu/client/dist/custom-elements/mayu-progress-bar-eb3e1ac8.js +1 -0
  21. data/lib/mayu/client/dist/custom-elements/mayu-progress-bar-eb3e1ac8.js.map +1 -0
  22. data/lib/mayu/client/dist/entries.json +3 -0
  23. data/lib/mayu/client/dist/main-4b49dbc4.js +1 -0
  24. data/lib/mayu/client/dist/main-4b49dbc4.js.br +0 -0
  25. data/lib/mayu/client/dist/main-4b49dbc4.js.map +1 -0
  26. data/lib/mayu/client/dist/main-4b49dbc4.js.map.br +0 -0
  27. data/lib/mayu/client/package.json +39 -0
  28. data/lib/mayu/client/rollup.config.js +81 -0
  29. data/lib/mayu/client/src/DecompressionStream.ts +15 -0
  30. data/lib/mayu/client/src/DecompressionStreamPolyfill.ts +43 -0
  31. data/lib/mayu/client/src/MimeTypes.ts +4 -0
  32. data/lib/mayu/client/src/NodeTree.ts +445 -0
  33. data/lib/mayu/client/src/custom-elements/mayu-alert.html +137 -0
  34. data/lib/mayu/client/src/custom-elements/mayu-alert.ts +62 -0
  35. data/lib/mayu/client/src/custom-elements/mayu-disconnected.html +134 -0
  36. data/lib/mayu/client/src/custom-elements/mayu-disconnected.ts +51 -0
  37. data/lib/mayu/client/src/custom-elements/mayu-exception.html +79 -0
  38. data/lib/mayu/client/src/custom-elements/mayu-exception.ts +28 -0
  39. data/lib/mayu/client/src/custom-elements/mayu-log.html +70 -0
  40. data/lib/mayu/client/src/custom-elements/mayu-log.ts +42 -0
  41. data/lib/mayu/client/src/custom-elements/mayu-ping.html +36 -0
  42. data/lib/mayu/client/src/custom-elements/mayu-ping.ts +53 -0
  43. data/lib/mayu/client/src/custom-elements/mayu-progress-bar.html +44 -0
  44. data/lib/mayu/client/src/custom-elements/mayu-progress-bar.ts +40 -0
  45. data/lib/mayu/client/src/custom-elements/types.d.ts +4 -0
  46. data/lib/mayu/client/src/global.d.ts +26 -0
  47. data/lib/mayu/client/src/h.ts +27 -0
  48. data/lib/mayu/client/src/logger.ts +56 -0
  49. data/lib/mayu/client/src/main.ts +271 -0
  50. data/lib/mayu/client/src/serializeEvent.ts +90 -0
  51. data/lib/mayu/client/src/stream.ts +175 -0
  52. data/lib/mayu/client/src/types.ts +1 -0
  53. data/lib/mayu/client/src/utils.ts +71 -0
  54. data/lib/mayu/client/tsconfig.json +18 -0
  55. data/lib/mayu/colors.rb +34 -0
  56. data/lib/mayu/commands/base.rb +22 -0
  57. data/lib/mayu/commands/build.rb +82 -0
  58. data/lib/mayu/commands.rb +53 -0
  59. data/lib/mayu/component/base.rb +177 -0
  60. data/lib/mayu/component/handler_ref.rb +99 -0
  61. data/lib/mayu/component/helpers.rb +93 -0
  62. data/lib/mayu/component/interface.rb +18 -0
  63. data/lib/mayu/component/wrapper.rb +165 -0
  64. data/lib/mayu/component.rb +54 -0
  65. data/lib/mayu/configuration.rb +195 -0
  66. data/lib/mayu/disable_sorbet.rb +23 -0
  67. data/lib/mayu/environment.rb +151 -0
  68. data/lib/mayu/event_stream.rb +158 -0
  69. data/lib/mayu/fetch.rb +88 -0
  70. data/lib/mayu/html.rb +53 -0
  71. data/lib/mayu/html.yaml +767 -0
  72. data/lib/mayu/message_cipher.rb +172 -0
  73. data/lib/mayu/message_cipher.test.rb +16 -0
  74. data/lib/mayu/metrics/collector.rb +161 -0
  75. data/lib/mayu/metrics/exporter.rb +47 -0
  76. data/lib/mayu/metrics/reporter.rb +187 -0
  77. data/lib/mayu/metrics.rb +82 -0
  78. data/lib/mayu/ref_counter.rb +57 -0
  79. data/lib/mayu/resources/README.md +14 -0
  80. data/lib/mayu/resources/asset.rb +71 -0
  81. data/lib/mayu/resources/assets.rb +76 -0
  82. data/lib/mayu/resources/dependency_graph.rb +306 -0
  83. data/lib/mayu/resources/dot_exporter.rb +167 -0
  84. data/lib/mayu/resources/generators/base.rb +18 -0
  85. data/lib/mayu/resources/generators/copy_file.rb +26 -0
  86. data/lib/mayu/resources/generators/image.rb +106 -0
  87. data/lib/mayu/resources/generators/write_file.rb +39 -0
  88. data/lib/mayu/resources/hot_swap/file_watcher.rb +69 -0
  89. data/lib/mayu/resources/hot_swap.rb +46 -0
  90. data/lib/mayu/resources/mermaid_exporter.rb +210 -0
  91. data/lib/mayu/resources/registry.rb +190 -0
  92. data/lib/mayu/resources/resolver/base.rb +32 -0
  93. data/lib/mayu/resources/resolver/filesystem.rb +94 -0
  94. data/lib/mayu/resources/resolver/static.rb +27 -0
  95. data/lib/mayu/resources/resolver.rb +13 -0
  96. data/lib/mayu/resources/resource.rb +150 -0
  97. data/lib/mayu/resources/transformers/__test__/css/adjacent_selectors.in.css +3 -0
  98. data/lib/mayu/resources/transformers/__test__/css/adjacent_selectors.out.css +6 -0
  99. data/lib/mayu/resources/transformers/__test__/css/attributes.in.css +3 -0
  100. data/lib/mayu/resources/transformers/__test__/css/attributes.out.css +6 -0
  101. data/lib/mayu/resources/transformers/__test__/css/composes.in.css +6 -0
  102. data/lib/mayu/resources/transformers/__test__/css/composes.out.css +10 -0
  103. data/lib/mayu/resources/transformers/__test__/css/element_selectors.in.css +3 -0
  104. data/lib/mayu/resources/transformers/__test__/css/element_selectors.out.css +6 -0
  105. data/lib/mayu/resources/transformers/__test__/css/has.in.css +7 -0
  106. data/lib/mayu/resources/transformers/__test__/css/has.out.css +10 -0
  107. data/lib/mayu/resources/transformers/__test__/css/media_queries.in.css +8 -0
  108. data/lib/mayu/resources/transformers/__test__/css/media_queries.out.css +12 -0
  109. data/lib/mayu/resources/transformers/__test__/css/pseudo_classes.in.css +5 -0
  110. data/lib/mayu/resources/transformers/__test__/css/pseudo_classes.out.css +6 -0
  111. data/lib/mayu/resources/transformers/__test__/haml/README.md +10 -0
  112. data/lib/mayu/resources/transformers/__test__/haml/case.haml +8 -0
  113. data/lib/mayu/resources/transformers/__test__/haml/case.rb +15 -0
  114. data/lib/mayu/resources/transformers/__test__/haml/class_names.haml +13 -0
  115. data/lib/mayu/resources/transformers/__test__/haml/class_names.rb +26 -0
  116. data/lib/mayu/resources/transformers/__test__/haml/comments.haml +5 -0
  117. data/lib/mayu/resources/transformers/__test__/haml/comments.rb +5 -0
  118. data/lib/mayu/resources/transformers/__test__/haml/css.haml +3 -0
  119. data/lib/mayu/resources/transformers/__test__/haml/css.rb +11 -0
  120. data/lib/mayu/resources/transformers/__test__/haml/dashes.haml +3 -0
  121. data/lib/mayu/resources/transformers/__test__/haml/dashes.rb +11 -0
  122. data/lib/mayu/resources/transformers/__test__/haml/early_return.haml +4 -0
  123. data/lib/mayu/resources/transformers/__test__/haml/early_return.rb +9 -0
  124. data/lib/mayu/resources/transformers/__test__/haml/early_return2.haml +3 -0
  125. data/lib/mayu/resources/transformers/__test__/haml/early_return2.rb +6 -0
  126. data/lib/mayu/resources/transformers/__test__/haml/handlers.haml +6 -0
  127. data/lib/mayu/resources/transformers/__test__/haml/handlers.rb +12 -0
  128. data/lib/mayu/resources/transformers/__test__/haml/if_else.haml +6 -0
  129. data/lib/mayu/resources/transformers/__test__/haml/if_else.rb +12 -0
  130. data/lib/mayu/resources/transformers/__test__/haml/interpolation.haml +8 -0
  131. data/lib/mayu/resources/transformers/__test__/haml/interpolation.rb +11 -0
  132. data/lib/mayu/resources/transformers/__test__/haml/object_ref_as_key.haml +1 -0
  133. data/lib/mayu/resources/transformers/__test__/haml/object_ref_as_key.rb +5 -0
  134. data/lib/mayu/resources/transformers/__test__/haml/props.haml +4 -0
  135. data/lib/mayu/resources/transformers/__test__/haml/props.rb +11 -0
  136. data/lib/mayu/resources/transformers/__test__/haml/slots.haml +5 -0
  137. data/lib/mayu/resources/transformers/__test__/haml/slots.rb +9 -0
  138. data/lib/mayu/resources/transformers/__test__/haml/slots_dynamic.haml +3 -0
  139. data/lib/mayu/resources/transformers/__test__/haml/slots_dynamic.rb +9 -0
  140. data/lib/mayu/resources/transformers/__test__/haml/slots_fallback.haml +3 -0
  141. data/lib/mayu/resources/transformers/__test__/haml/slots_fallback.rb +5 -0
  142. data/lib/mayu/resources/transformers/__test__/haml/spacing.haml +5 -0
  143. data/lib/mayu/resources/transformers/__test__/haml/spacing.rb +14 -0
  144. data/lib/mayu/resources/transformers/__test__/haml/spacing2.haml +10 -0
  145. data/lib/mayu/resources/transformers/__test__/haml/spacing2.rb +11 -0
  146. data/lib/mayu/resources/transformers/__test__/haml/spacing3.haml +3 -0
  147. data/lib/mayu/resources/transformers/__test__/haml/spacing3.rb +10 -0
  148. data/lib/mayu/resources/transformers/css/rouge_lexer.rb +841 -0
  149. data/lib/mayu/resources/transformers/css.rb +100 -0
  150. data/lib/mayu/resources/transformers/css.test.rb +87 -0
  151. data/lib/mayu/resources/transformers/haml.rb +984 -0
  152. data/lib/mayu/resources/transformers/haml.test.rb +114 -0
  153. data/lib/mayu/resources/types/README.md +36 -0
  154. data/lib/mayu/resources/types/base.rb +35 -0
  155. data/lib/mayu/resources/types/component.rb +198 -0
  156. data/lib/mayu/resources/types/image.rb +169 -0
  157. data/lib/mayu/resources/types/javascript.rb +50 -0
  158. data/lib/mayu/resources/types/nil.rb +23 -0
  159. data/lib/mayu/resources/types/stylesheet.rb +119 -0
  160. data/lib/mayu/resources/types/svg.rb +69 -0
  161. data/lib/mayu/resources/types.rb +37 -0
  162. data/lib/mayu/routes.rb +170 -0
  163. data/lib/mayu/routing/builder.rb +108 -0
  164. data/lib/mayu/routing/matcher.rb +58 -0
  165. data/lib/mayu/routing/routes.rb +85 -0
  166. data/lib/mayu/routing.rb +17 -0
  167. data/lib/mayu/server/app.rb +494 -0
  168. data/lib/mayu/server/controller.rb +152 -0
  169. data/lib/mayu/server/errors.rb +110 -0
  170. data/lib/mayu/server/file_server.rb +140 -0
  171. data/lib/mayu/server.rb +63 -0
  172. data/lib/mayu/session.rb +358 -0
  173. data/lib/mayu/state/README.md +6 -0
  174. data/lib/mayu/state/action_creator.rb +191 -0
  175. data/lib/mayu/state/action_wrapper.rb +30 -0
  176. data/lib/mayu/state/loader.rb +220 -0
  177. data/lib/mayu/state/store.rb +82 -0
  178. data/lib/mayu/state.rb +8 -0
  179. data/lib/mayu/state.test.rb +97 -0
  180. data/lib/mayu/utils.rb +114 -0
  181. data/lib/mayu/vdom/children.rb +117 -0
  182. data/lib/mayu/vdom/component_marshaler.rb +53 -0
  183. data/lib/mayu/vdom/css_attributes.rb +131 -0
  184. data/lib/mayu/vdom/descriptor.rb +151 -0
  185. data/lib/mayu/vdom/descriptor.test.rb +26 -0
  186. data/lib/mayu/vdom/dom.rb +239 -0
  187. data/lib/mayu/vdom/h.rb +22 -0
  188. data/lib/mayu/vdom/id_generator.rb +55 -0
  189. data/lib/mayu/vdom/interfaces.rb +186 -0
  190. data/lib/mayu/vdom/marshalling.rb +78 -0
  191. data/lib/mayu/vdom/reconciliation.rb +205 -0
  192. data/lib/mayu/vdom/reconciliation.test.rb +56 -0
  193. data/lib/mayu/vdom/special_elements.rb +108 -0
  194. data/lib/mayu/vdom/update_context.rb +180 -0
  195. data/lib/mayu/vdom/vdom.perf.test.rb +146 -0
  196. data/lib/mayu/vdom/vnode.rb +266 -0
  197. data/lib/mayu/vdom/vtree.rb +672 -0
  198. data/lib/mayu/vdom/vtree.test.rb +68 -0
  199. data/lib/mayu/vdom.rb +8 -0
  200. data/lib/mayu/vdom.test.rb +73 -0
  201. data/lib/mayu/version.rb +6 -0
  202. data/lib/mayu.rb +8 -0
  203. data/mayu-live.gemspec +70 -0
  204. metadata +612 -0
@@ -0,0 +1,239 @@
1
+ # typed: strict
2
+
3
+ require "cgi"
4
+
5
+ module Mayu
6
+ module VDOM
7
+ class DOM
8
+ extend T::Sig
9
+
10
+ class DOMException < StandardError
11
+ end
12
+
13
+ class CSSStyleDeclaration
14
+ extend T::Sig
15
+
16
+ sig { void }
17
+ def initialize
18
+ @properties = T.let({}, T::Hash[String, String])
19
+ end
20
+
21
+ sig { params(name: String).returns(String) }
22
+ def get_property_value(name)
23
+ @properties[name].to_s
24
+ end
25
+
26
+ sig do
27
+ params(name: String, value: T.any(String, Integer, Float)).returns(
28
+ self
29
+ )
30
+ end
31
+ def set_property(name, value)
32
+ @properties[name] = value.to_s
33
+ self
34
+ end
35
+
36
+ sig { params(name: String).returns(self) }
37
+ def remove_property(name)
38
+ @properties.delete(name)
39
+ self
40
+ end
41
+
42
+ sig { returns(String) }
43
+ def to_s
44
+ @properties.map { "#{_1}: #{_2};" }.join(" ")
45
+ end
46
+ end
47
+
48
+ class Node
49
+ extend T::Sig
50
+
51
+ sig { returns(Integer) }
52
+ attr_reader :id
53
+
54
+ sig { returns(T.nilable(Element)) }
55
+ attr_reader :parent
56
+
57
+ sig { returns(T.nilable(Node)) }
58
+ def previous_sibling = parent&.find_previous_sibling(self)
59
+
60
+ sig { returns(T.nilable(Node)) }
61
+ def next_sibling = parent&.find_next_sibling(self)
62
+
63
+ sig { params(document: DOM).void }
64
+ def initialize(document)
65
+ @document = T.let(document, DOM)
66
+ @id = T.let(@document.next_id!, Integer)
67
+ @parent = T.let(nil, T.nilable(Element))
68
+ end
69
+
70
+ sig { returns(T::Boolean) }
71
+ def text? = false
72
+ sig { returns(T::Boolean) }
73
+ def element? = false
74
+
75
+ sig { returns(String) }
76
+ def to_s = ""
77
+
78
+ sig do
79
+ params(new_parent: T.nilable(Element)).returns(T.nilable(Element))
80
+ end
81
+ def parent=(new_parent)
82
+ @parent&.remove_child(self)
83
+ @parent = new_parent
84
+ end
85
+
86
+ sig { params(node: Node).returns(self) }
87
+ def append_child(node)
88
+ raise DOMException, "Can't append children to #{self.class.name}"
89
+ end
90
+
91
+ sig do
92
+ params(new_node: Node, reference_node: T.nilable(Node)).returns(self)
93
+ end
94
+ def insert_before(new_node, reference_node = nil)
95
+ raise DOMException, "Can't insert children to #{self.class.name}"
96
+ end
97
+
98
+ sig { params(node: Node).returns(self) }
99
+ def remove_child(node)
100
+ raise DOMException, "Can't remove children from #{self.class.name}"
101
+ end
102
+ end
103
+
104
+ class Element < Node
105
+ sig { returns(T::Array[Node]) }
106
+ attr_reader :children
107
+
108
+ sig { returns(CSSStyleDeclaration) }
109
+ attr_reader :style
110
+
111
+ sig { params(document: DOM, tag_name: Symbol).void }
112
+ def initialize(document, tag_name)
113
+ super(document)
114
+ @tag_name = T.let(tag_name, Symbol)
115
+ @children = T.let([], T::Array[Node])
116
+ @attributes = T.let({}, T::Hash[String, String])
117
+ @style = T.let(CSSStyleDeclaration.new, CSSStyleDeclaration)
118
+ end
119
+
120
+ sig { returns(T::Boolean) }
121
+ def element? = true
122
+
123
+ sig { returns(String) }
124
+ def to_s
125
+ attrs = [
126
+ %{data-mayu-id="#{id}"},
127
+ @attributes.map { %{#{_1}="#{CGI.escape(_2)}"} }
128
+ ].flatten.join(" ")
129
+
130
+ if children.empty?
131
+ "<#{@tag_name} #{attrs} />"
132
+ else
133
+ "<#{@tag_name} #{attrs}>#{children.join}</#{@tag_name}>"
134
+ end
135
+ end
136
+
137
+ sig { params(name: String).returns(T.nilable(String)) }
138
+ def get_attribute(name)
139
+ @attributes[name]
140
+ end
141
+
142
+ sig { params(name: String, value: String).void }
143
+ def set_attribute(name, value)
144
+ @attributes[name] = value
145
+ end
146
+
147
+ sig { params(name: String).void }
148
+ def remove_attribute(name)
149
+ @attributes.delete(name)
150
+ end
151
+
152
+ sig { params(node: Node).returns(self) }
153
+ def append_child(node)
154
+ node.parent = self
155
+ @children.push(node)
156
+ self
157
+ end
158
+
159
+ sig do
160
+ params(new_node: Node, reference_node: T.nilable(Node)).returns(self)
161
+ end
162
+ def insert_before(new_node, reference_node = nil)
163
+ new_node.parent = self
164
+ index = @children.index(reference_node) || -1
165
+ @children.insert(index, new_node)
166
+ self
167
+ end
168
+
169
+ sig { params(node: Node).returns(self) }
170
+ def remove_child(node)
171
+ @children.delete(node)
172
+ self
173
+ end
174
+
175
+ sig { params(node: Node).returns(T.nilable(Node)) }
176
+ def find_previous_sibling(node)
177
+ index = @children.index(node).to_i
178
+ @children[index.pred] if index > 1
179
+ end
180
+
181
+ sig { params(node: Node).returns(T.nilable(Node)) }
182
+ def find_next_sibling(node)
183
+ index = @children.index(node).to_i
184
+ @children[index.succ] if index
185
+ end
186
+ end
187
+
188
+ class Text < Node
189
+ sig { params(document: DOM, data: String).void }
190
+ def initialize(document, data)
191
+ super(document)
192
+ @data = T.let(data, String)
193
+ end
194
+
195
+ sig { returns(T::Boolean) }
196
+ def text? = true
197
+
198
+ sig { returns(String) }
199
+ def to_s = @data
200
+ end
201
+
202
+ class Comment < Node
203
+ sig { params(document: DOM, data: String).void }
204
+ def initialize(document, data)
205
+ super(document)
206
+ @data = T.let(data, String)
207
+ end
208
+
209
+ sig { returns(T::Boolean) }
210
+ def comment? = true
211
+
212
+ sig { returns(String) }
213
+ def to_s = "<!-- mayu-id: #{id}. #{@data} -->"
214
+ end
215
+
216
+ sig { returns(Element) }
217
+ attr_reader :root
218
+
219
+ sig { void }
220
+ def initialize
221
+ @id_counter = T.let(0, Integer)
222
+ @root = T.let(create_element(:html), Element)
223
+ end
224
+
225
+ sig { params(tag_name: Symbol).returns(Element) }
226
+ def create_element(tag_name)
227
+ Element.new(self, tag_name)
228
+ end
229
+
230
+ sig { params(data: String).returns(Text) }
231
+ def create_text_node(data)
232
+ Text.new(self, data)
233
+ end
234
+
235
+ sig { returns(Integer) }
236
+ def next_id! = @id_counter += 1
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+
3
+ require "sorbet-runtime"
4
+
5
+ module Mayu
6
+ module VDOM
7
+ module H
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ type: Component::ElementType,
13
+ children: T.any(Component::Children, Component::ChildType),
14
+ props: T.untyped
15
+ ).returns(Descriptor)
16
+ end
17
+ def self.[](type, *children, **props)
18
+ T.unsafe(Descriptor)[type, *children, **props]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ # typed: strict
2
+
3
+ module Mayu
4
+ module VDOM
5
+ class IdGenerator
6
+ extend T::Sig
7
+
8
+ # ALPHABET = "🌱🌴🌵🌸🌺🌻🌼🌿🍀🍃"
9
+ # JOINER = ""
10
+ ALPHABET = "0123456789"
11
+ JOINER = ""
12
+
13
+ DIGITS = T.let(ALPHABET.chars.freeze, T::Array[String])
14
+
15
+ Type = T.type_alias { String }
16
+
17
+ sig { void }
18
+ def initialize
19
+ @counter = T.let(0, Integer)
20
+ end
21
+
22
+ sig { returns(Type) }
23
+ def next!
24
+ id = @counter.tap { @counter = @counter.succ }
25
+ number_to_base(id, DIGITS.length).map { DIGITS[_1] }.join(JOINER)
26
+ end
27
+
28
+ sig { returns(Integer) }
29
+ def marshal_dump
30
+ @counter
31
+ end
32
+
33
+ sig { params(counter: Integer).void }
34
+ def marshal_load(counter)
35
+ @counter = counter
36
+ end
37
+
38
+ private
39
+
40
+ sig { params(number: Integer, base: Integer).returns(T::Array[Integer]) }
41
+ def number_to_base(number, base)
42
+ return [0] if number.zero?
43
+
44
+ digits = []
45
+
46
+ until number.zero?
47
+ digits.unshift(number % base)
48
+ number /= base
49
+ end
50
+
51
+ digits
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,186 @@
1
+ # typed: strict
2
+
3
+ module Mayu
4
+ module VDOM
5
+ module Interfaces
6
+ module VTree
7
+ extend T::Sig
8
+ extend T::Helpers
9
+ abstract!
10
+
11
+ sig { abstract.returns(String) }
12
+ def next_id!
13
+ end
14
+
15
+ sig { abstract.returns(Session) }
16
+ def session
17
+ end
18
+
19
+ sig { abstract.params(path: String).void }
20
+ def navigate(path)
21
+ end
22
+
23
+ sig { abstract.params(type: Symbol, payload: T.untyped).void }
24
+ def action(type, payload)
25
+ end
26
+
27
+ sig { overridable.params(vnode: T.untyped).void }
28
+ def enqueue_update!(vnode)
29
+ end
30
+ end
31
+
32
+ module VNode
33
+ extend T::Sig
34
+ extend T::Helpers
35
+ abstract!
36
+
37
+ sig { abstract.returns(String) }
38
+ def id
39
+ end
40
+
41
+ sig { abstract.returns(Descriptor) }
42
+ def descriptor
43
+ end
44
+ end
45
+
46
+ module Descriptor
47
+ module Factory
48
+ extend T::Sig
49
+ extend T::Helpers
50
+ abstract!
51
+
52
+ sig { abstract.params(obj: T.untyped).returns(Descriptor) }
53
+ def or_text(obj)
54
+ end
55
+
56
+ sig { abstract.params(text_content: T.untyped).returns(Descriptor) }
57
+ def text(text_content)
58
+ end
59
+
60
+ sig { abstract.returns(Descriptor) }
61
+ def comment
62
+ end
63
+
64
+ sig do
65
+ abstract
66
+ .params(children: Component::Children, parent_type: T.untyped)
67
+ .returns(T::Array[Descriptor])
68
+ end
69
+ def clean(children, parent_type: nil)
70
+ end
71
+
72
+ sig do
73
+ abstract
74
+ .params(descriptors: T::Array[Descriptor])
75
+ .returns(T::Array[Descriptor])
76
+ end
77
+ def add_comments_between_texts(descriptors)
78
+ end
79
+ end
80
+
81
+ extend T::Sig
82
+ extend T::Helpers
83
+ abstract!
84
+
85
+ TEXT = :TEXT
86
+ COMMENT = :COMMENT
87
+
88
+ sig { overridable.returns(T::Boolean) }
89
+ def text? = type == TEXT
90
+
91
+ sig { overridable.returns(T::Boolean) }
92
+ def comment? = type == COMMENT
93
+
94
+ sig { overridable.returns(T::Boolean) }
95
+ def element? = type.is_a?(Symbol)
96
+
97
+ sig { abstract.returns(T::Boolean) }
98
+ def component?
99
+ end
100
+
101
+ sig { abstract.returns(Component::ElementType) }
102
+ def type
103
+ end
104
+
105
+ sig { abstract.returns(Component::Props) }
106
+ def props
107
+ end
108
+
109
+ sig { abstract.returns(T.untyped) }
110
+ def key
111
+ end
112
+
113
+ sig { abstract.returns(String) }
114
+ def slot
115
+ end
116
+
117
+ sig { overridable.returns(Children[Descriptor]) }
118
+ def children = props[:children]
119
+
120
+ sig { overridable.returns(T::Boolean) }
121
+ def has_children? = children.any?
122
+
123
+ sig { overridable.returns(String) }
124
+ def text = props[:text_content].to_s
125
+
126
+ sig { abstract.returns(T.class_of(Component::Base)) }
127
+ def component_class
128
+ end
129
+
130
+ sig { returns(Descriptor) }
131
+ def itself = self
132
+
133
+ sig do
134
+ type_parameters(:R)
135
+ .params(
136
+ block:
137
+ T.proc.params(arg0: Descriptor).returns(T.type_parameter(:R))
138
+ )
139
+ .returns(T.type_parameter(:R))
140
+ end
141
+ def then(&block) = yield self
142
+
143
+ ##
144
+ # This is used for hash comparisons,
145
+ # https://ruby-doc.org/3.2.0/Hash.html#class-Hash-label-User-Defined+Hash+Keys
146
+ sig { overridable.returns(Integer) }
147
+ def hash
148
+ [type, slot, key, type == :input && props[:type]].hash
149
+ end
150
+
151
+ ##
152
+ # This is used for hash comparisons,
153
+ # https://ruby-doc.org/3.2.0/Hash.html#class-Hash-label-User-Defined+Hash+Keys
154
+ sig { abstract.params(other: T.untyped).returns(T::Boolean) }
155
+ def eql?(other)
156
+ end
157
+
158
+ sig do
159
+ abstract.params(other: Interfaces::Descriptor).returns(T::Boolean)
160
+ end
161
+ def same?(other)
162
+ end
163
+ end
164
+
165
+ module Children
166
+ extend T::Sig
167
+ extend T::Helpers
168
+ extend T::Generic
169
+ include Enumerable
170
+ Elem = type_member { { upper: Descriptor } }
171
+ abstract!
172
+
173
+ sig do
174
+ abstract
175
+ .params(
176
+ name: T.nilable(String),
177
+ fallback: T.nilable(T.proc.returns(Descriptor))
178
+ )
179
+ .returns(T.nilable(T.any(Descriptor, T::Array[Descriptor])))
180
+ end
181
+ def slot(name = nil, &fallback)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,78 @@
1
+ # typed: strict
2
+
3
+ module Mayu
4
+ module VDOM
5
+ module Marshalling
6
+ extend T::Sig
7
+
8
+ sig { params(vtree: VTree).returns(String) }
9
+ def self.dump(vtree)
10
+ Marshal.dump(vtree)
11
+ end
12
+
13
+ sig do
14
+ params(dumped: String, session: Session, task: Async::Task).returns(
15
+ VTree
16
+ )
17
+ end
18
+ def self.restore(dumped, session:, task: Async::Task.current)
19
+ vtree =
20
+ Marshal.restore(
21
+ dumped,
22
+ ->(obj) do
23
+ case obj
24
+ when VDOM::VTree
25
+ obj.instance_variable_set(:@session, session)
26
+ obj.instance_variable_set(:@task, task)
27
+ obj
28
+ when VDOM::ComponentMarshaler
29
+ case obj.type
30
+ in klass:
31
+ klass
32
+ in component:
33
+ T.cast(
34
+ session.environment.resources.load_resource(component).type,
35
+ Resources::Types::Component
36
+ ).component
37
+ else
38
+ obj.type
39
+ end
40
+ else
41
+ obj
42
+ end
43
+ end
44
+ )
45
+
46
+ vtree.root&.traverse do |vnode|
47
+ vnode.instance_variable_set(:@vtree, vtree)
48
+ end
49
+
50
+ vtree
51
+ end
52
+
53
+ sig { params(props: Component::Props).returns(Component::Props) }
54
+ def self.dump_props(props)
55
+ props.transform_values { |value| dump_value(value) }
56
+ end
57
+
58
+ sig { params(state: Component::State).returns(Component::State) }
59
+ def self.dump_state(state)
60
+ state.transform_values { |value| dump_value(value) }
61
+ end
62
+
63
+ sig { params(value: T.untyped).returns(T.untyped) }
64
+ def self.dump_value(value)
65
+ case value
66
+ when Hash
67
+ value.transform_values { dump_value(_1) }
68
+ when Array
69
+ value.map { dump_value(_1) }
70
+ when Component
71
+ ComponentMarshaler.new(value)
72
+ else
73
+ value
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end