quantum-framework 0.9.0__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.
Files changed (262) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/commands/__init__.py +15 -0
  4. quantum/cli/commands/build.py +417 -0
  5. quantum/cli/commands/dev.py +185 -0
  6. quantum/cli/commands/docs.py +329 -0
  7. quantum/cli/commands/lint.py +523 -0
  8. quantum/cli/commands/migrate.py +527 -0
  9. quantum/cli/commands/new.py +622 -0
  10. quantum/cli/commands/serve.py +190 -0
  11. quantum/cli/commands/test.py +193 -0
  12. quantum/cli/deploy.py +810 -0
  13. quantum/cli/hot_reload.py +951 -0
  14. quantum/cli/jobs.py +356 -0
  15. quantum/cli/mq.py +582 -0
  16. quantum/cli/pkg.py +390 -0
  17. quantum/cli/runner.py +547 -0
  18. quantum/cli/server_process.py +159 -0
  19. quantum/cli/utils.py +334 -0
  20. quantum/compiler/__init__.py +30 -0
  21. quantum/compiler/base_generator.py +367 -0
  22. quantum/compiler/cli.py +295 -0
  23. quantum/compiler/expression_transformer.py +444 -0
  24. quantum/compiler/javascript/__init__.py +10 -0
  25. quantum/compiler/javascript/generator.py +659 -0
  26. quantum/compiler/optimizer.py +270 -0
  27. quantum/compiler/python/__init__.py +10 -0
  28. quantum/compiler/python/generator.py +883 -0
  29. quantum/compiler/python/runtime.py +863 -0
  30. quantum/compiler/transpiler.py +330 -0
  31. quantum/core/__init__.py +3 -0
  32. quantum/core/ast_nodes.py +2611 -0
  33. quantum/core/expression_diagnostics.py +87 -0
  34. quantum/core/expression_stdlib.py +148 -0
  35. quantum/core/expressions.py +591 -0
  36. quantum/core/features/agents/src/__init__.py +30 -0
  37. quantum/core/features/agents/src/ast_node.py +540 -0
  38. quantum/core/features/conditionals/src/__init__.py +8 -0
  39. quantum/core/features/conditionals/src/ast_node.py +68 -0
  40. quantum/core/features/data_fetching/src/__init__.py +21 -0
  41. quantum/core/features/data_fetching/src/ast_node.py +312 -0
  42. quantum/core/features/data_fetching/src/desktop_adapter.py +351 -0
  43. quantum/core/features/data_fetching/src/html_adapter.py +474 -0
  44. quantum/core/features/data_fetching/src/parser.py +225 -0
  45. quantum/core/features/data_import/src/__init__.py +0 -0
  46. quantum/core/features/data_import/src/ast_node.py +291 -0
  47. quantum/core/features/data_import/src/runtime.py +538 -0
  48. quantum/core/features/dump/src/__init__.py +12 -0
  49. quantum/core/features/dump/src/ast_node.py +106 -0
  50. quantum/core/features/dump/src/parser.py +61 -0
  51. quantum/core/features/dump/src/runtime.py +246 -0
  52. quantum/core/features/functions/src/__init__.py +8 -0
  53. quantum/core/features/functions/src/ast_node.py +149 -0
  54. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  55. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  56. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  57. quantum/core/features/invocation/src/__init__.py +0 -0
  58. quantum/core/features/invocation/src/ast_node.py +146 -0
  59. quantum/core/features/invocation/src/runtime.py +327 -0
  60. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  61. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  62. quantum/core/features/knowledge_base/src/parser.py +82 -0
  63. quantum/core/features/logging/src/__init__.py +12 -0
  64. quantum/core/features/logging/src/ast_node.py +111 -0
  65. quantum/core/features/logging/src/parser.py +50 -0
  66. quantum/core/features/logging/src/runtime.py +190 -0
  67. quantum/core/features/loops/src/__init__.py +8 -0
  68. quantum/core/features/loops/src/ast_node.py +60 -0
  69. quantum/core/features/query/src/__init__.py +0 -0
  70. quantum/core/features/query/src/database_service.py +322 -0
  71. quantum/core/features/query/src/query_validators.py +20 -0
  72. quantum/core/features/state_management/src/__init__.py +11 -0
  73. quantum/core/features/state_management/src/ast_node.py +228 -0
  74. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  75. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  76. quantum/core/features/terminal_engine/src/parser.py +361 -0
  77. quantum/core/features/testing_engine/src/__init__.py +41 -0
  78. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  79. quantum/core/features/testing_engine/src/parser.py +604 -0
  80. quantum/core/features/theming/src/__init__.py +48 -0
  81. quantum/core/features/theming/src/ast_node.py +137 -0
  82. quantum/core/features/theming/src/presets.py +405 -0
  83. quantum/core/features/ui_engine/src/__init__.py +20 -0
  84. quantum/core/features/ui_engine/src/ast_nodes.py +1854 -0
  85. quantum/core/features/ui_engine/src/parser.py +1106 -0
  86. quantum/core/features/websocket/src/__init__.py +24 -0
  87. quantum/core/features/websocket/src/ast_node.py +247 -0
  88. quantum/core/html_compat.py +299 -0
  89. quantum/core/parser.py +1235 -0
  90. quantum/core/parser_registry.py +213 -0
  91. quantum/core/parsers/__init__.py +76 -0
  92. quantum/core/parsers/ai/__init__.py +12 -0
  93. quantum/core/parsers/ai/agent_parser.py +106 -0
  94. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  95. quantum/core/parsers/ai/llm_parser.py +78 -0
  96. quantum/core/parsers/ai/team_parser.py +88 -0
  97. quantum/core/parsers/base.py +322 -0
  98. quantum/core/parsers/composition/__init__.py +10 -0
  99. quantum/core/parsers/composition/import_parser.py +50 -0
  100. quantum/core/parsers/composition/slot_parser.py +48 -0
  101. quantum/core/parsers/control_flow/__init__.py +11 -0
  102. quantum/core/parsers/control_flow/if_parser.py +68 -0
  103. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  104. quantum/core/parsers/control_flow/set_parser.py +89 -0
  105. quantum/core/parsers/data/__init__.py +12 -0
  106. quantum/core/parsers/data/data_parser.py +217 -0
  107. quantum/core/parsers/data/invoke_parser.py +116 -0
  108. quantum/core/parsers/data/query_parser.py +188 -0
  109. quantum/core/parsers/data/transaction_parser.py +77 -0
  110. quantum/core/parsers/events/__init__.py +9 -0
  111. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  112. quantum/core/parsers/forms/__init__.py +11 -0
  113. quantum/core/parsers/forms/action_parser.py +54 -0
  114. quantum/core/parsers/forms/flash_parser.py +34 -0
  115. quantum/core/parsers/forms/redirect_parser.py +33 -0
  116. quantum/core/parsers/functions/__init__.py +11 -0
  117. quantum/core/parsers/functions/function_parser.py +137 -0
  118. quantum/core/parsers/functions/param_parser.py +66 -0
  119. quantum/core/parsers/functions/return_parser.py +31 -0
  120. quantum/core/parsers/html/__init__.py +10 -0
  121. quantum/core/parsers/html/component_call_parser.py +130 -0
  122. quantum/core/parsers/html/html_parser.py +115 -0
  123. quantum/core/parsers/jobs/__init__.py +11 -0
  124. quantum/core/parsers/jobs/job_parser.py +71 -0
  125. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  126. quantum/core/parsers/jobs/thread_parser.py +57 -0
  127. quantum/core/parsers/messaging/__init__.py +17 -0
  128. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  130. quantum/core/parsers/messaging/message_parser.py +114 -0
  131. quantum/core/parsers/messaging/queue_parser.py +61 -0
  132. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  133. quantum/core/parsers/persistence/__init__.py +9 -0
  134. quantum/core/parsers/persistence/persist_parser.py +64 -0
  135. quantum/core/parsers/routing/__init__.py +9 -0
  136. quantum/core/parsers/routing/route_parser.py +41 -0
  137. quantum/core/parsers/scripting/__init__.py +12 -0
  138. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  139. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  140. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  141. quantum/core/parsers/scripting/python_parser.py +49 -0
  142. quantum/core/parsers/services/__init__.py +12 -0
  143. quantum/core/parsers/services/dump_parser.py +52 -0
  144. quantum/core/parsers/services/file_parser.py +48 -0
  145. quantum/core/parsers/services/log_parser.py +46 -0
  146. quantum/core/parsers/services/mail_parser.py +65 -0
  147. quantum/core/tiers.py +82 -0
  148. quantum/packages/__init__.py +28 -0
  149. quantum/packages/manager.py +413 -0
  150. quantum/packages/manifest.py +351 -0
  151. quantum/packages/registry.py +399 -0
  152. quantum/packages/resolver.py +336 -0
  153. quantum/plugins/__init__.py +33 -0
  154. quantum/plugins/hooks.py +329 -0
  155. quantum/plugins/loader.py +479 -0
  156. quantum/plugins/manifest.py +336 -0
  157. quantum/plugins/registry.py +371 -0
  158. quantum/runtime/__init__.py +28 -0
  159. quantum/runtime/action_handler.py +443 -0
  160. quantum/runtime/adapters/__init__.py +88 -0
  161. quantum/runtime/adapters/memory_adapter.py +690 -0
  162. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  163. quantum/runtime/adapters/redis_adapter.py +582 -0
  164. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  165. quantum/runtime/agent_service.py +1133 -0
  166. quantum/runtime/api_server.py +86 -0
  167. quantum/runtime/ast_cache.py +506 -0
  168. quantum/runtime/auth_service.py +267 -0
  169. quantum/runtime/component.py +990 -0
  170. quantum/runtime/component_composer.py +319 -0
  171. quantum/runtime/component_resolver.py +174 -0
  172. quantum/runtime/database_service.py +598 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +286 -0
  176. quantum/runtime/executor_registry.py +171 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +262 -0
  184. quantum/runtime/executors/control_flow/__init__.py +11 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +93 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +307 -0
  187. quantum/runtime/executors/control_flow/set_executor.py +412 -0
  188. quantum/runtime/executors/data/__init__.py +12 -0
  189. quantum/runtime/executors/data/data_executor.py +145 -0
  190. quantum/runtime/executors/data/invoke_executor.py +176 -0
  191. quantum/runtime/executors/data/query_executor.py +256 -0
  192. quantum/runtime/executors/data/transaction_executor.py +91 -0
  193. quantum/runtime/executors/jobs/__init__.py +11 -0
  194. quantum/runtime/executors/jobs/job_executor.py +190 -0
  195. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  196. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  197. quantum/runtime/executors/messaging/__init__.py +17 -0
  198. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  199. quantum/runtime/executors/messaging/message_executor.py +174 -0
  200. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  201. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  202. quantum/runtime/executors/scripting/__init__.py +11 -0
  203. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  204. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  205. quantum/runtime/executors/scripting/python_executor.py +249 -0
  206. quantum/runtime/executors/services/__init__.py +12 -0
  207. quantum/runtime/executors/services/dump_executor.py +72 -0
  208. quantum/runtime/executors/services/file_executor.py +89 -0
  209. quantum/runtime/executors/services/log_executor.py +77 -0
  210. quantum/runtime/executors/services/mail_executor.py +81 -0
  211. quantum/runtime/expression_cache.py +498 -0
  212. quantum/runtime/file_upload_service.py +326 -0
  213. quantum/runtime/function_registry.py +118 -0
  214. quantum/runtime/game_builder.py +166 -0
  215. quantum/runtime/game_code_generator.py +2371 -0
  216. quantum/runtime/game_templates.py +2006 -0
  217. quantum/runtime/godot_code_generator.py +4681 -0
  218. quantum/runtime/godot_templates.py +1449 -0
  219. quantum/runtime/job_executor.py +1599 -0
  220. quantum/runtime/knowledge_service.py +500 -0
  221. quantum/runtime/llm_cache.py +100 -0
  222. quantum/runtime/llm_providers.py +704 -0
  223. quantum/runtime/llm_service.py +287 -0
  224. quantum/runtime/logging_setup.py +140 -0
  225. quantum/runtime/message_broker.py +364 -0
  226. quantum/runtime/message_queue_service.py +571 -0
  227. quantum/runtime/param_validation.py +184 -0
  228. quantum/runtime/pypy_compat.py +315 -0
  229. quantum/runtime/python_bridge.py +698 -0
  230. quantum/runtime/query_validators.py +304 -0
  231. quantum/runtime/renderer.py +733 -0
  232. quantum/runtime/service_container.py +444 -0
  233. quantum/runtime/terminal_builder.py +76 -0
  234. quantum/runtime/terminal_code_generator.py +607 -0
  235. quantum/runtime/terminal_templates.py +243 -0
  236. quantum/runtime/testing_builder.py +77 -0
  237. quantum/runtime/testing_code_generator.py +833 -0
  238. quantum/runtime/testing_templates.py +85 -0
  239. quantum/runtime/ui_builder.py +188 -0
  240. quantum/runtime/ui_desktop_adapter.py +1730 -0
  241. quantum/runtime/ui_desktop_templates.py +307 -0
  242. quantum/runtime/ui_html_adapter.py +2691 -0
  243. quantum/runtime/ui_html_templates.py +2297 -0
  244. quantum/runtime/ui_mobile_adapter.py +1832 -0
  245. quantum/runtime/ui_mobile_templates.py +1003 -0
  246. quantum/runtime/ui_textual_adapter.py +1866 -0
  247. quantum/runtime/ui_textual_templates.py +45 -0
  248. quantum/runtime/ui_tokens.py +465 -0
  249. quantum/runtime/ui_validator.py +365 -0
  250. quantum/runtime/validators.py +256 -0
  251. quantum/runtime/web_server.py +1766 -0
  252. quantum/runtime/websocket_adapter.py +501 -0
  253. quantum/runtime/websocket_service.py +585 -0
  254. quantum/runtime/websocket_transport.py +289 -0
  255. quantum/runtime/wsgi.py +101 -0
  256. quantum/utils/__init__.py +1 -0
  257. quantum_framework-0.9.0.dist-info/METADATA +244 -0
  258. quantum_framework-0.9.0.dist-info/RECORD +262 -0
  259. quantum_framework-0.9.0.dist-info/WHEEL +5 -0
  260. quantum_framework-0.9.0.dist-info/entry_points.txt +2 -0
  261. quantum_framework-0.9.0.dist-info/licenses/LICENSE +21 -0
  262. quantum_framework-0.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,77 @@
1
+ """
2
+ Transaction Parser - Parse q:transaction statements
3
+
4
+ Handles atomic database transactions.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import TransactionNode
11
+
12
+
13
+ class TransactionParser(BaseTagParser):
14
+ """
15
+ Parser for q:transaction statements.
16
+
17
+ Supports:
18
+ - Atomic transaction blocks
19
+ - Automatic rollback on error
20
+ - Nested statement execution
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['transaction']
26
+
27
+ def parse(self, element: ET.Element) -> TransactionNode:
28
+ """
29
+ Parse q:transaction statement.
30
+
31
+ Args:
32
+ element: XML element for q:transaction
33
+
34
+ Returns:
35
+ TransactionNode AST node
36
+ """
37
+ # datasource= is optional. Requiring it was stricter than the runtime
38
+ # (DatabaseService.begin_transaction defaults it) and stricter than
39
+ # everything written against it: all four q:transaction blocks in this
40
+ # repository omit it, and three of them are tests that had been
41
+ # failing on this line — "Transaction requires 'datasource'
42
+ # attribute" — rather than on anything about transactions.
43
+ datasource = self.get_attr(element, 'datasource')
44
+
45
+ transaction_node = TransactionNode(datasource or '')
46
+
47
+ # Isolation level. Everything written in this repository and in the
48
+ # docs spells it isolationLevel; the parser read `isolation`, so the
49
+ # level was silently dropped every time. Both spellings work.
50
+ transaction_node.isolation = (
51
+ self.get_attr(element, 'isolationLevel')
52
+ or self.get_attr(element, 'isolation')
53
+ )
54
+
55
+ # Parse child statements
56
+ for child in element:
57
+ statement = self.parse_statement(child)
58
+ if statement:
59
+ transaction_node.add_statement(statement)
60
+
61
+ if not datasource:
62
+ # Take it from the queries being wrapped, which is what the author
63
+ # means by wrapping them. Only if none of them names one does this
64
+ # fall back to "default".
65
+ transaction_node.datasource = (
66
+ self._datasource_of_children(transaction_node) or 'default'
67
+ )
68
+
69
+ return transaction_node
70
+
71
+ def _datasource_of_children(self, transaction_node) -> str:
72
+ """The datasource of the first child query that names one."""
73
+ for statement in getattr(transaction_node, 'statements', []) or []:
74
+ name = getattr(statement, 'datasource', None)
75
+ if name:
76
+ return name
77
+ return ''
@@ -0,0 +1,9 @@
1
+ """
2
+ Events Parsers
3
+
4
+ Parsers for event-related tags: dispatchEvent
5
+ """
6
+
7
+ from .dispatch_event_parser import DispatchEventParser
8
+
9
+ __all__ = ['DispatchEventParser']
@@ -0,0 +1,44 @@
1
+ """
2
+ DispatchEvent Parser - Parse q:dispatchEvent statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import DispatchEventNode
9
+
10
+
11
+ class DispatchEventParser(BaseTagParser):
12
+ """
13
+ Parser for q:dispatchEvent statements.
14
+
15
+ Examples:
16
+ <q:dispatchEvent event="userCreated" data="{userData}" />
17
+ <q:dispatchEvent event="orderPlaced" queue="orders" priority="high" />
18
+ """
19
+
20
+ @property
21
+ def tag_names(self) -> List[str]:
22
+ return ['dispatchEvent']
23
+
24
+ def parse(self, element: ET.Element) -> DispatchEventNode:
25
+ """Parse q:dispatchEvent element"""
26
+ event = element.get('event')
27
+
28
+ if not event:
29
+ from quantum.core.parser import QuantumParseError
30
+ raise QuantumParseError("dispatchEvent requires 'event' attribute")
31
+
32
+ dispatch_node = DispatchEventNode(event)
33
+
34
+ # Optional attributes
35
+ dispatch_node.data = element.get('data')
36
+ dispatch_node.queue = element.get('queue')
37
+ dispatch_node.exchange = element.get('exchange')
38
+ dispatch_node.routing_key = element.get('routingKey')
39
+ dispatch_node.priority = element.get('priority', 'normal')
40
+ dispatch_node.delay = element.get('delay')
41
+ dispatch_node.ttl = element.get('ttl')
42
+ dispatch_node.metadata = element.get('metadata')
43
+
44
+ return dispatch_node
@@ -0,0 +1,11 @@
1
+ """
2
+ Forms & Actions Parsers
3
+
4
+ Parsers for form handling tags: action, redirect, flash
5
+ """
6
+
7
+ from .action_parser import ActionParser
8
+ from .redirect_parser import RedirectParser
9
+ from .flash_parser import FlashParser
10
+
11
+ __all__ = ['ActionParser', 'RedirectParser', 'FlashParser']
@@ -0,0 +1,54 @@
1
+ """
2
+ Action Parser - Parse q:action statements for form handling
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import ActionNode
9
+
10
+
11
+ class ActionParser(BaseTagParser):
12
+ """
13
+ Parser for q:action statements.
14
+
15
+ Examples:
16
+ <q:action name="createUser" method="POST">
17
+ <q:param name="email" type="email" required="true" />
18
+ <q:query datasource="db">...</q:query>
19
+ <q:redirect url="/users" flash="User created!" />
20
+ </q:action>
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['action']
26
+
27
+ def parse(self, element: ET.Element) -> ActionNode:
28
+ """Parse q:action element"""
29
+ name = element.get('name', '')
30
+ method = element.get('method', 'POST')
31
+ action_node = ActionNode(name, method)
32
+
33
+ # Parse optional attributes
34
+ if element.get('csrf') == 'false':
35
+ action_node.validate_csrf = False
36
+ if element.get('rate_limit'):
37
+ action_node.rate_limit = element.get('rate_limit')
38
+ if element.get('require_auth') == 'true':
39
+ action_node.require_auth = True
40
+
41
+ # Parse children (params, statements)
42
+ for child in element:
43
+ child_type = self._get_element_name(child)
44
+
45
+ if child_type == 'param':
46
+ param = self.parse_param(child)
47
+ action_node.add_param(param)
48
+ else:
49
+ # Parse other statements (query, set, redirect, etc.)
50
+ statement = self.parse_child(child)
51
+ if statement:
52
+ action_node.add_statement(statement)
53
+
54
+ return action_node
@@ -0,0 +1,34 @@
1
+ """
2
+ Flash Parser - Parse q:flash statements for flash messages
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import FlashNode
9
+
10
+
11
+ class FlashParser(BaseTagParser):
12
+ """
13
+ Parser for q:flash statements.
14
+
15
+ Examples:
16
+ <q:flash type="success" message="User created!" />
17
+ <q:flash type="error" message="{errorMessage}" />
18
+ <q:flash type="warning">Please verify your email</q:flash>
19
+ """
20
+
21
+ @property
22
+ def tag_names(self) -> List[str]:
23
+ return ['flash']
24
+
25
+ def parse(self, element: ET.Element) -> FlashNode:
26
+ """Parse q:flash element"""
27
+ flash_type = element.get('type', 'info')
28
+ message = element.get('message')
29
+
30
+ # If message not in attribute, check text content
31
+ if not message and element.text:
32
+ message = element.text.strip()
33
+
34
+ return FlashNode(message, flash_type)
@@ -0,0 +1,33 @@
1
+ """
2
+ Redirect Parser - Parse q:redirect statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import RedirectNode
9
+
10
+
11
+ class RedirectParser(BaseTagParser):
12
+ """
13
+ Parser for q:redirect statements.
14
+
15
+ Examples:
16
+ <q:redirect url="/thank-you" />
17
+ <q:redirect url="/users/{userId}" />
18
+ <q:redirect url="/products" flash="Product created!" />
19
+ <q:redirect url="/error" status="500" flash="Error occurred" />
20
+ """
21
+
22
+ @property
23
+ def tag_names(self) -> List[str]:
24
+ return ['redirect']
25
+
26
+ def parse(self, element: ET.Element) -> RedirectNode:
27
+ """Parse q:redirect element"""
28
+ # Accept to= as an alias for url= (both appear across examples)
29
+ url = element.get('url') or element.get('to', '')
30
+ flash = element.get('flash')
31
+ status = int(element.get('status', '302'))
32
+
33
+ return RedirectNode(url, flash, status)
@@ -0,0 +1,11 @@
1
+ """
2
+ Functions Parsers
3
+
4
+ Parsers for function-related tags: function, return, param
5
+ """
6
+
7
+ from .function_parser import FunctionParser
8
+ from .return_parser import ReturnParser
9
+ from .param_parser import ParamParser
10
+
11
+ __all__ = ['FunctionParser', 'ReturnParser', 'ParamParser']
@@ -0,0 +1,137 @@
1
+ """
2
+ Function Parser - Parse q:function statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import FunctionNode
9
+
10
+
11
+ class FunctionParser(BaseTagParser):
12
+ """
13
+ Parser for q:function statements.
14
+
15
+ Examples:
16
+ <q:function name="calculateTotal" returnType="number">
17
+ <q:param name="items" type="array" />
18
+ <q:set name="total" value="0" />
19
+ <q:loop array="{items}" item="item">
20
+ <q:set name="total" value="{total + item.price}" />
21
+ </q:loop>
22
+ </q:function>
23
+
24
+ <q:function name="getUser" endpoint="/api/users/{id}" method="GET">
25
+ <q:param name="id" type="integer" source="path" />
26
+ <q:query datasource="db">SELECT * FROM users WHERE id = :id</q:query>
27
+ </q:function>
28
+ """
29
+
30
+ @property
31
+ def tag_names(self) -> List[str]:
32
+ return ['function']
33
+
34
+ def parse(self, element: ET.Element) -> FunctionNode:
35
+ """Parse q:function element"""
36
+ name = element.get('name')
37
+
38
+ if not name:
39
+ from quantum.core.parser import QuantumParseError
40
+ raise QuantumParseError("Function requires 'name' attribute")
41
+
42
+ func_node = FunctionNode(name)
43
+
44
+ # Core attributes
45
+ func_node.return_type = element.get('returnType', 'any')
46
+ func_node.scope = element.get('scope', 'component')
47
+ func_node.access = element.get('access', 'public')
48
+ func_node.description = element.get('description')
49
+ func_node.hint = element.get('hint')
50
+
51
+ # Validation
52
+ func_node.validate_params = element.get('validate', 'false').lower() == 'true'
53
+
54
+ # Performance
55
+ cache_attr = element.get('cache')
56
+ if cache_attr:
57
+ if cache_attr.lower() == 'true':
58
+ func_node.cache = True
59
+ elif cache_attr.endswith('s'): # "60s"
60
+ func_node.cache = True
61
+ try:
62
+ func_node.cache_ttl = int(cache_attr[:-1])
63
+ except ValueError:
64
+ pass
65
+
66
+ func_node.memoize = element.get('memoize', 'false').lower() == 'true'
67
+ func_node.pure = element.get('pure', 'false').lower() == 'true'
68
+
69
+ # Behavior
70
+ func_node.async_func = element.get('async', 'false').lower() == 'true'
71
+
72
+ retry_attr = element.get('retry')
73
+ if retry_attr:
74
+ try:
75
+ func_node.retry = int(retry_attr)
76
+ except ValueError:
77
+ pass
78
+
79
+ timeout_attr = element.get('timeout')
80
+ if timeout_attr:
81
+ func_node.timeout = timeout_attr
82
+
83
+ # REST API (optional)
84
+ endpoint = element.get('endpoint')
85
+ if endpoint:
86
+ method = element.get('method', 'GET')
87
+ func_node.enable_rest(endpoint, method)
88
+
89
+ # REST-specific attributes
90
+ if element.get('produces'):
91
+ func_node.rest_config.produces = element.get('produces')
92
+
93
+ if element.get('consumes'):
94
+ func_node.rest_config.consumes = element.get('consumes')
95
+
96
+ if element.get('auth'):
97
+ func_node.rest_config.auth = element.get('auth')
98
+
99
+ if element.get('roles'):
100
+ roles_str = element.get('roles')
101
+ func_node.rest_config.roles = [r.strip() for r in roles_str.split(',')]
102
+
103
+ if element.get('rateLimit'):
104
+ func_node.rest_config.rate_limit = element.get('rateLimit')
105
+
106
+ cors_attr = element.get('cors')
107
+ if cors_attr and cors_attr.lower() == 'true':
108
+ func_node.rest_config.cors = True
109
+
110
+ status_attr = element.get('status')
111
+ if status_attr:
112
+ try:
113
+ func_node.rest_config.status = int(status_attr)
114
+ except ValueError:
115
+ pass
116
+
117
+ # Parse function params and body
118
+ for child in element:
119
+ child_type = self._get_element_name(child)
120
+
121
+ if child_type == 'param':
122
+ param = self.parse_param(child)
123
+ func_node.add_param(param)
124
+ elif child_type == 'return':
125
+ # ReturnParser is deliberately not in the tag registry (it is
126
+ # an internal parser), so parse_child() returns None for it —
127
+ # which silently dropped every <q:return> from every function
128
+ # body, making functions return nothing. Parse it directly.
129
+ from quantum.core.parsers.functions.return_parser import ReturnParser
130
+ func_node.add_statement(ReturnParser(self._parser).parse(child))
131
+ else:
132
+ # Parse body statements
133
+ statement = self.parse_child(child)
134
+ if statement:
135
+ func_node.add_statement(statement)
136
+
137
+ return func_node
@@ -0,0 +1,66 @@
1
+ """
2
+ Param Parser - Parse q:param statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import QuantumParam
9
+
10
+
11
+ class ParamParser(BaseTagParser):
12
+ """
13
+ Parser for q:param statements.
14
+
15
+ Examples:
16
+ <q:param name="email" type="email" required="true" />
17
+ <q:param name="password" type="string" minlength="8" />
18
+ <q:param name="age" type="integer" min="0" max="150" />
19
+ """
20
+
21
+ @property
22
+ def tag_names(self) -> List[str]:
23
+ return ['param']
24
+
25
+ def parse(self, element: ET.Element) -> QuantumParam:
26
+ """Parse q:param element"""
27
+ param = QuantumParam(
28
+ name=element.get('name', ''),
29
+ type=element.get('type', 'string'),
30
+ required=element.get('required', 'false').lower() == 'true',
31
+ default=element.get('default'),
32
+ validation=element.get('validation'),
33
+ description=element.get('description')
34
+ )
35
+
36
+ # REST-specific
37
+ param.source = element.get('source', 'auto')
38
+
39
+ # Validation
40
+ param.validate_rule = element.get('validate')
41
+ param.pattern = element.get('pattern')
42
+ param.min = element.get('min')
43
+ param.max = element.get('max')
44
+
45
+ minlength_str = element.get('minlength')
46
+ if minlength_str:
47
+ try:
48
+ param.minlength = int(minlength_str)
49
+ except ValueError:
50
+ pass
51
+
52
+ maxlength_str = element.get('maxlength')
53
+ if maxlength_str:
54
+ try:
55
+ param.maxlength = int(maxlength_str)
56
+ except ValueError:
57
+ pass
58
+
59
+ param.range = element.get('range')
60
+ param.enum = element.get('enum')
61
+
62
+ # File upload
63
+ param.maxsize = element.get('maxsize')
64
+ param.accept = element.get('accept')
65
+
66
+ return param
@@ -0,0 +1,31 @@
1
+ """
2
+ Return Parser - Parse q:return statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import QuantumReturn
9
+
10
+
11
+ class ReturnParser(BaseTagParser):
12
+ """
13
+ Parser for q:return statements.
14
+
15
+ Examples:
16
+ <q:return name="result" type="string" value="{computedValue}" />
17
+ <q:return type="integer" value="42" />
18
+ """
19
+
20
+ @property
21
+ def tag_names(self) -> List[str]:
22
+ return ['return']
23
+
24
+ def parse(self, element: ET.Element) -> QuantumReturn:
25
+ """Parse q:return element"""
26
+ return QuantumReturn(
27
+ name=element.get('name'),
28
+ type=element.get('type', 'string'),
29
+ value=element.get('value', ''),
30
+ description=element.get('description')
31
+ )
@@ -0,0 +1,10 @@
1
+ """
2
+ HTML Parsers
3
+
4
+ Parsers for HTML elements and component calls.
5
+ """
6
+
7
+ from .html_parser import HTMLParser
8
+ from .component_call_parser import ComponentCallParser
9
+
10
+ __all__ = ['HTMLParser', 'ComponentCallParser']
@@ -0,0 +1,130 @@
1
+ """
2
+ Component Call Parser - Parse component invocations
3
+
4
+ Handles parsing of component calls (PascalCase tags).
5
+ """
6
+
7
+ from typing import List, Optional, Dict, Any
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser
10
+ from quantum.core.ast_nodes import ComponentCallNode, TextNode
11
+
12
+
13
+ class ComponentCallParser(BaseTagParser):
14
+ """
15
+ Parser for component call elements.
16
+
17
+ Component calls are identified by PascalCase naming convention:
18
+ - <MyComponent /> -> calls imported component "MyComponent"
19
+ - <UserCard name="John" /> -> calls "UserCard" with props
20
+
21
+ These are similar to React/Vue component usage.
22
+ """
23
+
24
+ @property
25
+ def tag_names(self) -> List[str]:
26
+ """
27
+ Component call parser doesn't register for specific tags.
28
+ Instead, it's called when a PascalCase tag is detected.
29
+ """
30
+ return []
31
+
32
+ def parse(self, element: ET.Element) -> ComponentCallNode:
33
+ """
34
+ Parse component call element.
35
+
36
+ Args:
37
+ element: XML element representing component call
38
+
39
+ Returns:
40
+ ComponentCallNode AST node
41
+ """
42
+ component_name = self._get_local_name(element)
43
+
44
+ # Get props from attributes
45
+ props = self._parse_props(element)
46
+
47
+ # Create component call node
48
+ call_node = ComponentCallNode(component_name, props)
49
+
50
+ # Parse children (slot content)
51
+ call_node.children = self._parse_children(element)
52
+
53
+ return call_node
54
+
55
+ def _get_local_name(self, element: ET.Element) -> str:
56
+ """Extract local name from element tag."""
57
+ tag = element.tag
58
+ if '}' in tag:
59
+ return tag.split('}')[1]
60
+ if ':' in tag:
61
+ return tag.split(':')[1]
62
+ return tag
63
+
64
+ def _parse_props(self, element: ET.Element) -> Dict[str, Any]:
65
+ """
66
+ Parse element attributes as component props.
67
+
68
+ Handles:
69
+ - Simple string values: name="John"
70
+ - Databinding expressions: user="{currentUser}"
71
+ - Boolean shorthand: disabled (treated as disabled="true")
72
+ """
73
+ props = {}
74
+
75
+ for key, value in element.attrib.items():
76
+ # Skip namespace declarations
77
+ if key.startswith('xmlns'):
78
+ continue
79
+
80
+ # Handle namespaced attributes
81
+ if '}' in key:
82
+ key = key.split('}')[1]
83
+
84
+ props[key] = value
85
+
86
+ return props
87
+
88
+ def _parse_children(self, element: ET.Element) -> List:
89
+ """Parse child elements as slot content."""
90
+ children = []
91
+
92
+ # Add leading text if present
93
+ if element.text and element.text.strip():
94
+ children.append(TextNode(element.text))
95
+
96
+ # Parse child elements
97
+ for child in element:
98
+ child_node = self.parse_statement(child)
99
+ if child_node:
100
+ children.append(child_node)
101
+
102
+ # Add tail text after child
103
+ if child.tail and child.tail.strip():
104
+ children.append(TextNode(child.tail))
105
+
106
+ return children
107
+
108
+ @staticmethod
109
+ def is_component_call(tag_name: str) -> bool:
110
+ """
111
+ Check if tag name represents a component call.
112
+
113
+ Components use PascalCase naming:
114
+ - MyComponent -> True
115
+ - UserCard -> True
116
+ - div -> False
117
+ - myComponent -> False
118
+ """
119
+ if not tag_name:
120
+ return False
121
+
122
+ # Must start with uppercase letter
123
+ if not tag_name[0].isupper():
124
+ return False
125
+
126
+ # Should not be all uppercase (likely a constant/builtin)
127
+ if tag_name.isupper():
128
+ return False
129
+
130
+ return True