quantum-framework 0.18.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 (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -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 +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,659 @@
1
+ """
2
+ JavaScript Code Generator
3
+ =========================
4
+
5
+ Generates JavaScript code from Quantum AST nodes.
6
+ """
7
+
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Optional, List, Set
11
+
12
+ # Add paths
13
+
14
+ from quantum.compiler.base_generator import CodeGenerator
15
+ from quantum.compiler.expression_transformer import ExpressionTransformer
16
+ from quantum.core.ast_nodes import (
17
+ QuantumNode, ComponentNode, ApplicationNode, SetNode, LoopNode,
18
+ IfNode, FunctionNode, HTMLNode, TextNode, QueryNode, ActionNode,
19
+ ImportNode, SlotNode, ComponentCallNode, PythonNode, PyImportNode,
20
+ RedirectNode, FlashNode, DocTypeNode, CommentNode
21
+ )
22
+
23
+
24
+ class JavaScriptGenerator(CodeGenerator):
25
+ """
26
+ Generates JavaScript code from Quantum AST.
27
+
28
+ Produces clean ES6+ JavaScript with module exports.
29
+ """
30
+
31
+ def __init__(self):
32
+ super().__init__()
33
+ self.expr_transformer = ExpressionTransformer(target='javascript')
34
+ self.imports: Set[str] = set()
35
+ self.component_name: str = ''
36
+ self.in_render: bool = False
37
+ self.indent_str = " " # 2 spaces for JS
38
+
39
+ def file_extension(self) -> str:
40
+ return '.js'
41
+
42
+ def generate_header(self) -> str:
43
+ """Generate JavaScript file header."""
44
+ lines = [
45
+ '/**',
46
+ ' * Generated by Quantum Transpiler',
47
+ ' * Do not edit directly - changes will be overwritten.',
48
+ ' */',
49
+ '',
50
+ "import { Component, escape, bind, range } from 'quantum-runtime';",
51
+ '',
52
+ ]
53
+ return '\n'.join(lines)
54
+
55
+ def generate_footer(self) -> str:
56
+ """Generate file footer with exports."""
57
+ if self.component_name:
58
+ return f'\nexport default {self.component_name};\n'
59
+ return ''
60
+
61
+ def transpile_expression(self, expr: str) -> str:
62
+ """Transpile Quantum expression to JavaScript."""
63
+ return self.expr_transformer.transform(expr)
64
+
65
+ # =========================================================================
66
+ # Component & Application
67
+ # =========================================================================
68
+
69
+ def visit_ComponentNode(self, node: ComponentNode) -> str:
70
+ """Generate JavaScript class for component."""
71
+ self.component_name = node.name or 'Component'
72
+
73
+ # Get statements
74
+ statements = getattr(node, 'statements', None) or getattr(node, 'children', None) or []
75
+
76
+ # Class definition
77
+ self.emit(f'class {self.component_name} extends Component {{')
78
+ self.indent()
79
+
80
+ # Constructor
81
+ self.emit('constructor(props = {}) {')
82
+ self.indent()
83
+ self.emit('super(props);')
84
+ self.dedent()
85
+ self.emit('}')
86
+ self.emit_blank()
87
+
88
+ # Render method
89
+ self.emit('render() {')
90
+ self.indent()
91
+ self.in_render = True
92
+
93
+ # Initialize
94
+ self.emit('let _html = [];')
95
+ self.emit('const { ...props } = this.props;')
96
+ self.emit_blank()
97
+
98
+ # Process statements
99
+ self.push_scope()
100
+ for child in statements:
101
+ self.visit(child)
102
+ self.pop_scope()
103
+
104
+ self.emit_blank()
105
+ self.emit("return _html.join('\\n');")
106
+
107
+ self.in_render = False
108
+ self.dedent()
109
+ self.emit('}')
110
+
111
+ self.dedent()
112
+ self.emit('}')
113
+
114
+ return self.component_name
115
+
116
+ # =========================================================================
117
+ # State Management
118
+ # =========================================================================
119
+
120
+ def visit_SetNode(self, node: SetNode) -> str:
121
+ """Generate variable assignment."""
122
+ name = node.name
123
+ value = getattr(node, 'value', None)
124
+
125
+ # Determine if let or const
126
+ keyword = 'let' if not self.is_declared(name) else ''
127
+
128
+ if value is None:
129
+ if keyword:
130
+ self.emit(f'{keyword} {name} = null;')
131
+ else:
132
+ self.emit(f'{name} = null;')
133
+ elif self.is_expression(str(value)):
134
+ expr = self.transpile_expression(str(value))
135
+ if keyword:
136
+ self.emit(f'{keyword} {name} = {expr};')
137
+ else:
138
+ self.emit(f'{name} = {expr};')
139
+ elif self.is_literal(str(value)):
140
+ if keyword:
141
+ self.emit(f'{keyword} {name} = {value};')
142
+ else:
143
+ self.emit(f'{name} = {value};')
144
+ else:
145
+ # String value
146
+ escaped = str(value).replace("'", "\\'")
147
+ if keyword:
148
+ self.emit(f"{keyword} {name} = '{escaped}';")
149
+ else:
150
+ self.emit(f"{name} = '{escaped}';")
151
+
152
+ self.declare_var(name)
153
+ return name
154
+
155
+ # =========================================================================
156
+ # Control Flow
157
+ # =========================================================================
158
+
159
+ def visit_LoopNode(self, node: LoopNode) -> str:
160
+ """Generate for loop."""
161
+ var = getattr(node, 'var_name', None) or getattr(node, 'var', None) or 'item'
162
+ index_var = getattr(node, 'index_name', None) or getattr(node, 'index', None)
163
+ collection = getattr(node, 'items', None) or getattr(node, 'collection', None)
164
+ from_val = getattr(node, 'from_value', None) or getattr(node, 'from_val', None)
165
+ to_val = getattr(node, 'to_value', None) or getattr(node, 'to_val', None)
166
+ step = getattr(node, 'step_value', None) or getattr(node, 'step', None) or 1
167
+ body = getattr(node, 'body', None) or getattr(node, 'children', None) or []
168
+
169
+ if collection:
170
+ # Collection-based loop
171
+ coll_expr = self.transpile_expression(str(collection))
172
+
173
+ if index_var:
174
+ self.emit(f'{coll_expr}.forEach(({var}, {index_var}) => {{')
175
+ else:
176
+ self.emit(f'for (const {var} of {coll_expr}) {{')
177
+ else:
178
+ # Range-based loop (inclusive end)
179
+ start = from_val if from_val is not None else 0
180
+ end = to_val if to_val is not None else 0
181
+
182
+ if self.is_expression(str(start)):
183
+ start = self.transpile_expression(str(start))
184
+ if self.is_expression(str(end)):
185
+ end = self.transpile_expression(str(end))
186
+
187
+ self.emit(f'for (let {var} = {start}; {var} <= {end}; {var} += {step}) {{')
188
+
189
+ self.indent()
190
+ self.push_scope()
191
+ self.declare_var(var)
192
+ if index_var:
193
+ self.declare_var(index_var)
194
+
195
+ for child in body:
196
+ self.visit(child)
197
+
198
+ self.pop_scope()
199
+ self.dedent()
200
+
201
+ if collection and index_var:
202
+ self.emit('});')
203
+ else:
204
+ self.emit('}')
205
+
206
+ return ''
207
+
208
+ def visit_IfNode(self, node: IfNode) -> str:
209
+ """Generate if/else if/else."""
210
+ condition = getattr(node, 'condition', None) or getattr(node, 'test', None)
211
+
212
+ if condition:
213
+ cond_expr = self.transpile_expression(str(condition))
214
+ self.emit(f'if ({cond_expr}) {{')
215
+ else:
216
+ self.emit('if (true) {')
217
+
218
+ self.indent()
219
+ self.push_scope()
220
+
221
+ # Process if-body
222
+ has_content = False
223
+ else_children = []
224
+ elseif_children = []
225
+
226
+ for child in getattr(node, 'children', []) or []:
227
+ child_type = type(child).__name__
228
+
229
+ if child_type == 'ElseNode' or (hasattr(child, 'tag') and child.tag == 'q:else'):
230
+ else_children = getattr(child, 'children', []) or []
231
+ elif child_type == 'ElseIfNode' or (hasattr(child, 'tag') and child.tag == 'q:elseif'):
232
+ elseif_children.append(child)
233
+ else:
234
+ self.visit(child)
235
+ has_content = True
236
+
237
+ self.pop_scope()
238
+ self.dedent()
239
+ self.emit('}')
240
+
241
+ # Handle else if
242
+ for elseif in elseif_children:
243
+ elseif_cond = getattr(elseif, 'condition', None) or getattr(elseif, 'test', None)
244
+ if elseif_cond:
245
+ cond_expr = self.transpile_expression(str(elseif_cond))
246
+ self.emit(f'else if ({cond_expr}) {{')
247
+ else:
248
+ self.emit('else if (true) {')
249
+
250
+ self.indent()
251
+ for child in getattr(elseif, 'children', []) or []:
252
+ self.visit(child)
253
+ self.dedent()
254
+ self.emit('}')
255
+
256
+ # Handle else
257
+ if else_children:
258
+ self.emit('else {')
259
+ self.indent()
260
+ for child in else_children:
261
+ self.visit(child)
262
+ self.dedent()
263
+ self.emit('}')
264
+
265
+ return ''
266
+
267
+ # =========================================================================
268
+ # Functions
269
+ # =========================================================================
270
+
271
+ def visit_FunctionNode(self, node: FunctionNode) -> str:
272
+ """Generate function definition."""
273
+ name = node.name or 'anonymousFunction'
274
+ params = getattr(node, 'params', '') or ''
275
+
276
+ if isinstance(params, str):
277
+ param_list = [p.strip() for p in params.split(',') if p.strip()]
278
+ else:
279
+ param_list = list(params) if params else []
280
+
281
+ param_str = ', '.join(param_list)
282
+ self.emit(f'function {name}({param_str}) {{')
283
+
284
+ self.indent()
285
+ self.push_scope()
286
+
287
+ for param in param_list:
288
+ param_name = param.split('=')[0].strip()
289
+ self.declare_var(param_name)
290
+
291
+ for child in getattr(node, 'children', []) or []:
292
+ self.visit(child)
293
+
294
+ self.pop_scope()
295
+ self.dedent()
296
+ self.emit('}')
297
+ self.emit_blank()
298
+
299
+ return name
300
+
301
+ def visit_ReturnNode(self, node) -> str:
302
+ """Generate return statement."""
303
+ value = getattr(node, 'value', None)
304
+
305
+ if value:
306
+ expr = self.transpile_expression(str(value))
307
+ self.emit(f'return {expr};')
308
+ else:
309
+ self.emit('return;')
310
+
311
+ return ''
312
+
313
+ # =========================================================================
314
+ # HTML Rendering
315
+ # =========================================================================
316
+
317
+ def visit_HTMLNode(self, node: HTMLNode) -> str:
318
+ """Generate HTML element."""
319
+ tag = node.tag or 'div'
320
+ attributes = getattr(node, 'attributes', {}) or {}
321
+ children = node.children or []
322
+
323
+ # Build attributes
324
+ attr_parts = []
325
+ for key, value in attributes.items():
326
+ if value is None:
327
+ attr_parts.append(key)
328
+ elif self.is_expression(str(value)):
329
+ expr = self.transpile_expression(str(value))
330
+ attr_parts.append(f'{key}="${{escape({expr})}}"')
331
+ else:
332
+ attr_parts.append(f'{key}="{value}"')
333
+
334
+ attr_str = ' ' + ' '.join(attr_parts) if attr_parts else ''
335
+
336
+ # Self-closing tags
337
+ self_closing = tag.lower() in ('br', 'hr', 'img', 'input', 'meta', 'link')
338
+
339
+ if self_closing:
340
+ self.emit(f'_html.push(`<{tag}{attr_str} />`);')
341
+ elif not children:
342
+ self.emit(f'_html.push(`<{tag}{attr_str}></{tag}>`);')
343
+ else:
344
+ self.emit(f'_html.push(`<{tag}{attr_str}>`);')
345
+
346
+ for child in children:
347
+ self.visit(child)
348
+
349
+ self.emit(f"_html.push('</{tag}>');")
350
+
351
+ return ''
352
+
353
+ def visit_TextNode(self, node: TextNode) -> str:
354
+ """Generate text content."""
355
+ content = getattr(node, 'content', '') or getattr(node, 'text', '') or ''
356
+
357
+ if not content.strip():
358
+ return ''
359
+
360
+ # Handle databinding with template literals
361
+ if '{' in content and '}' in content:
362
+ # Convert {expr} to ${expr}
363
+ import re
364
+ js_template = re.sub(r'\{([^}]+)\}', r'${\1}', content)
365
+ self.emit(f'_html.push(`{js_template}`);')
366
+ else:
367
+ escaped = content.replace('`', '\\`')
368
+ self.emit(f'_html.push(`{escaped}`);')
369
+
370
+ return ''
371
+
372
+ def visit_DocTypeNode(self, node: DocTypeNode) -> str:
373
+ """Generate DOCTYPE."""
374
+ self.emit("_html.push('<!DOCTYPE html>');")
375
+ return ''
376
+
377
+ def visit_CommentNode(self, node: CommentNode) -> str:
378
+ """Generate HTML comment."""
379
+ content = getattr(node, 'content', '') or getattr(node, 'text', '') or ''
380
+ self.emit(f"_html.push('<!-- {content} -->');")
381
+ return ''
382
+
383
+ # =========================================================================
384
+ # Actions & Redirects
385
+ # =========================================================================
386
+
387
+ def visit_RedirectNode(self, node: RedirectNode) -> str:
388
+ """Generate redirect."""
389
+ url = getattr(node, 'url', '/') or getattr(node, 'to', '/')
390
+
391
+ if self.is_expression(str(url)):
392
+ url_expr = self.transpile_expression(str(url))
393
+ self.emit(f'window.location.href = {url_expr};')
394
+ else:
395
+ self.emit(f"window.location.href = '{url}';")
396
+
397
+ return ''
398
+
399
+ def visit_FlashNode(self, node: FlashNode) -> str:
400
+ """Generate flash message."""
401
+ message = getattr(node, 'message', '')
402
+ category = getattr(node, 'category', 'info') or getattr(node, 'type', 'info')
403
+
404
+ if self.is_expression(str(message)):
405
+ msg_expr = self.transpile_expression(str(message))
406
+ self.emit(f"flash({msg_expr}, '{category}');")
407
+ else:
408
+ self.emit(f"flash('{message}', '{category}');")
409
+
410
+ return ''
411
+
412
+ # =========================================================================
413
+ # Data Nodes (Phase 2)
414
+ # =========================================================================
415
+
416
+ def visit_QueryNode(self, node) -> str:
417
+ """Generate database query (client-side fetch)."""
418
+ name = getattr(node, 'name', 'result')
419
+ endpoint = getattr(node, 'endpoint', None) or f'/api/query/{name}'
420
+
421
+ self.emit(f'// Query: {name}')
422
+ self.emit(f'const {name} = await fetch({repr(endpoint)}).then(r => r.json());')
423
+ self.declare_var(name)
424
+
425
+ return name
426
+
427
+ def visit_DataNode(self, node) -> str:
428
+ """Generate data import code."""
429
+ name = getattr(node, 'name', 'data')
430
+ source = getattr(node, 'source', '')
431
+ data_type = getattr(node, 'data_type', None) or getattr(node, 'type', 'json')
432
+
433
+ source_expr = self.transpile_expression(str(source)) if self.is_expression(str(source)) else repr(source)
434
+
435
+ self.emit(f'// Data import: {name}')
436
+ self.emit(f'const {name} = await fetch({source_expr}).then(r => r.json());')
437
+ self.declare_var(name)
438
+
439
+ return name
440
+
441
+ def visit_InvokeNode(self, node) -> str:
442
+ """Generate HTTP invocation."""
443
+ name = getattr(node, 'name', 'result')
444
+ url = getattr(node, 'url', None)
445
+ method = getattr(node, 'method', 'GET')
446
+ function = getattr(node, 'function', None)
447
+
448
+ self.emit(f'// Invoke: {name}')
449
+
450
+ if function:
451
+ func_expr = self.transpile_expression(str(function)) if self.is_expression(str(function)) else function
452
+ self.emit(f'const {name} = {func_expr}();')
453
+ elif url:
454
+ url_expr = self.transpile_expression(str(url)) if self.is_expression(str(url)) else repr(url)
455
+
456
+ # Build headers and body from children
457
+ headers = {}
458
+ body = None
459
+ for child in getattr(node, 'children', []) or []:
460
+ child_type = type(child).__name__
461
+ if child_type == 'InvokeHeaderNode':
462
+ headers[getattr(child, 'name', '')] = getattr(child, 'value', '')
463
+ elif child_type == 'InvokeBodyNode':
464
+ body = getattr(child, 'content', None)
465
+
466
+ self.emit(f'const {name} = await invoke({url_expr}, {{')
467
+ self.indent()
468
+ self.emit(f"method: '{method}',")
469
+ if headers:
470
+ import json
471
+ self.emit(f'headers: {json.dumps(headers)},')
472
+ if body:
473
+ body_expr = self.transpile_expression(str(body)) if self.is_expression(str(body)) else repr(body)
474
+ self.emit(f'body: {body_expr}')
475
+ self.dedent()
476
+ self.emit('});')
477
+ else:
478
+ self.emit(f'const {name} = null;')
479
+
480
+ self.declare_var(name)
481
+ return name
482
+
483
+ def visit_FileNode(self, node) -> str:
484
+ """Generate file upload code."""
485
+ action = getattr(node, 'action', 'upload')
486
+ file_var = getattr(node, 'file', '')
487
+ result_var = getattr(node, 'result', None) or getattr(node, 'name', 'fileResult')
488
+
489
+ file_expr = self.transpile_expression(str(file_var)) if self.is_expression(str(file_var)) else file_var
490
+
491
+ self.emit(f'// File operation: {action}')
492
+ if action == 'upload':
493
+ self.emit(f'const formData = new FormData();')
494
+ self.emit(f'formData.append("file", {file_expr});')
495
+ self.emit(f'const {result_var} = await fetch("/api/upload", {{')
496
+ self.indent()
497
+ self.emit('method: "POST",')
498
+ self.emit('body: formData')
499
+ self.dedent()
500
+ self.emit('}).then(r => r.json());')
501
+ else:
502
+ self.emit(f'const {result_var} = null;')
503
+
504
+ self.declare_var(result_var)
505
+ return result_var
506
+
507
+ def visit_MailNode(self, node) -> str:
508
+ """Generate email sending code (via API)."""
509
+ to = getattr(node, 'to', '')
510
+ from_addr = getattr(node, 'from_', '') or getattr(node, 'sender', '')
511
+ subject = getattr(node, 'subject', '')
512
+
513
+ to_expr = self.transpile_expression(str(to)) if self.is_expression(str(to)) else repr(to)
514
+ subject_expr = self.transpile_expression(str(subject)) if self.is_expression(str(subject)) else repr(subject)
515
+
516
+ self.emit('// Send email via API')
517
+ self.emit('await fetch("/api/mail", {')
518
+ self.indent()
519
+ self.emit('method: "POST",')
520
+ self.emit('headers: { "Content-Type": "application/json" },')
521
+ self.emit(f'body: JSON.stringify({{ to: {to_expr}, subject: {subject_expr} }})')
522
+ self.dedent()
523
+ self.emit('});')
524
+
525
+ return ''
526
+
527
+ def visit_ActionNode(self, node) -> str:
528
+ """Generate action handler."""
529
+ name = getattr(node, 'name', 'action')
530
+ method = getattr(node, 'method', 'POST')
531
+
532
+ self.emit(f'// Action: {name}')
533
+ self.emit(f'async function action_{name}(event) {{')
534
+ self.indent()
535
+ self.emit('event.preventDefault();')
536
+ self.emit('const formData = new FormData(event.target);')
537
+ self.emit_blank()
538
+
539
+ self.push_scope()
540
+ for child in getattr(node, 'children', []) or []:
541
+ self.visit(child)
542
+ self.pop_scope()
543
+
544
+ self.dedent()
545
+ self.emit('}')
546
+ self.emit_blank()
547
+
548
+ return f'action_{name}'
549
+
550
+ # =========================================================================
551
+ # Async Nodes (Phase 3)
552
+ # =========================================================================
553
+
554
+ def visit_JobNode(self, node) -> str:
555
+ """Generate job queue code (Web Worker or setTimeout)."""
556
+ name = getattr(node, 'name', 'job')
557
+ action = getattr(node, 'action', 'define')
558
+ delay = getattr(node, 'delay', None)
559
+
560
+ self.emit(f'// Job: {name}')
561
+
562
+ if action == 'define':
563
+ self.emit(f'async function job_{name}(params) {{')
564
+ self.indent()
565
+ self.push_scope()
566
+ for child in getattr(node, 'children', []) or []:
567
+ self.visit(child)
568
+ self.pop_scope()
569
+ self.dedent()
570
+ self.emit('}')
571
+ self.emit_blank()
572
+ elif action == 'dispatch':
573
+ if delay:
574
+ # Parse delay to milliseconds
575
+ self.emit(f'setTimeout(() => job_{name}(), parseDelay({repr(delay)}));')
576
+ else:
577
+ self.emit(f'queueMicrotask(() => job_{name}());')
578
+
579
+ return f'job_{name}'
580
+
581
+ def visit_ScheduleNode(self, node) -> str:
582
+ """Generate scheduled task (using setInterval)."""
583
+ name = getattr(node, 'name', 'task')
584
+ interval = getattr(node, 'interval', None)
585
+
586
+ self.emit(f'// Scheduled task: {name}')
587
+
588
+ self.emit(f'async function scheduled_{name}() {{')
589
+ self.indent()
590
+ self.push_scope()
591
+ for child in getattr(node, 'children', []) or []:
592
+ self.visit(child)
593
+ self.pop_scope()
594
+ self.dedent()
595
+ self.emit('}')
596
+ self.emit_blank()
597
+
598
+ if interval:
599
+ self.emit(f'const {name}_interval = setInterval(scheduled_{name}, parseDelay({repr(interval)}));')
600
+
601
+ return f'scheduled_{name}'
602
+
603
+ def visit_ThreadNode(self, node) -> str:
604
+ """Generate async execution (Promise-based)."""
605
+ name = getattr(node, 'name', 'thread')
606
+ action = getattr(node, 'action', 'run')
607
+ on_complete = getattr(node, 'on_complete', None) or getattr(node, 'onComplete', None)
608
+
609
+ self.emit(f'// Async thread: {name}')
610
+
611
+ if action == 'run':
612
+ self.emit(f'const thread_{name} = (async () => {{')
613
+ self.indent()
614
+ self.push_scope()
615
+ for child in getattr(node, 'children', []) or []:
616
+ self.visit(child)
617
+ self.pop_scope()
618
+ self.dedent()
619
+ if on_complete:
620
+ self.emit(f'}})().then({on_complete});')
621
+ else:
622
+ self.emit('})();')
623
+ elif action == 'join':
624
+ self.emit(f'await thread_{name};')
625
+
626
+ return f'thread_{name}'
627
+
628
+ def visit_ParallelNode(self, node) -> str:
629
+ """Generate parallel execution (Promise.all)."""
630
+ name = getattr(node, 'name', 'parallel')
631
+
632
+ self.emit(f'// Parallel execution: {name}')
633
+ self.emit(f'const {name}_results = await Promise.all([')
634
+ self.indent()
635
+
636
+ for idx, child in enumerate(getattr(node, 'children', []) or []):
637
+ child_type = type(child).__name__
638
+ if child_type in ('ThreadNode', 'TaskNode', 'InvokeNode'):
639
+ self.emit('(async () => {')
640
+ self.indent()
641
+ self.visit(child)
642
+ self.dedent()
643
+ self.emit('})(),')
644
+ else:
645
+ self.visit(child)
646
+
647
+ self.dedent()
648
+ self.emit(']);')
649
+ self.declare_var(f'{name}_results')
650
+
651
+ return name
652
+
653
+ # =========================================================================
654
+ # Comments
655
+ # =========================================================================
656
+
657
+ def emit_comment(self, comment: str):
658
+ """Emit JavaScript comment."""
659
+ self.emit(f'// {comment}')